How to center absolute dynamic width ul submenu? - css

I found a lot of posts about centering submenu <ul> absolute positioned, but none of them solved the problem of center the submenu that have dynamic width determined by the text length of the <li> children...
Most of those posts offer a solution based on the use of negative margin-left,
and this means that it can work only for a specific width, but not for dynamic width!
So I have prepared a quick FIDDLE HERE with a very basic menu,
please can you help me to figure out how is possible to automatically center submenus?
nav {
background-color: red;
}
ul {
background-color: rgb(88, 164, 228);
padding: 0;
margin: 0;
list-style-type: none;
}
li {
display: inline-block;
margin: 0 20px;
}
ul ul {
background: rgb(119, 193, 255);
position: absolute;
outline: 1px solid black;
}
ul ul li {
margin: 0;
display: block;
}
<nav>
<ul>
<li>Menu</li>
<li>Menu
<ul>
<li>aa aa aa aa</li>
<li>bb bb</li>
</ul>
</li>
<li>Menu
<ul>
<li>cc cc cc</li>
<li>dd dd dd dd dd</li>
<li>ee ee ee</li>
</ul>
</li>
<li>Menu
<ul>
<li>ff ff</li>
<li>gg gg</li>
</ul>
</li>
<li>Menu</li>
<li>Menu</li>
</ul>
</nav>

Related

CSS unordered list aligning

I've searched around and found a lot of questions about this problem, but none of the answers I tried seemed to work in my case. So I have a unordered list inside of the nav tag and I want the list to be centered relative to the parent nav tag. But the list is always a bit to the right and never in the center no matter what I tried.
HTML pretty straight forward:
<nav>
<ul>
<li>MENU</li>
<li>Opt 1</li>
<li>Opt 2</li>
<li>Opt 3</li>
</ul>
</nav>
Here is the CSS so far:
nav {
float: left;
width:15%;
margin: 0;
padding:0;
background:gray;
text-align:center;
}
nav ul {
list-style-type: none;
color:blue;
}
Any ideas how can I get this to work?
try this
nav ul {
list-style-type: none;
padding: 0;
margin: 0;
}
this is because ul have a padding and margin applied to it by browsers by default you need to remove them
nav {
float: left;
width: 50%;
margin: 0;
padding: 0;
background: gray;
text-align: center;
}
nav ul {
list-style-type: none;
color: blue;
margin: 0;
padding: 0;
}
<nav>
<ul>
<li>MENU</li>
<li>Opt 1
</li>
<li>Opt 2
</li>
<li>Opt 3
</li>
</ul>
</nav>
Test this:
<nav>
<ul>
<li>MENU</li>
<li>Opt 1</li>
<li>Opt 2</li>
<li>Opt 3</li>
</ul>
</nav>
nav {
display:table;
margin:0 auto;
padding : 10px;
}

CSS Dropdown Menu not showing child elements

I am working on getting my CSS Menu setup, I have followed some tutorials but got myself stuck after hiding some secondary menu items. I just want the items to show up right below their parents. (Not to the side like most tutorials I've seen)
My code is here
http://codepen.io/anon/pen/pJMdqv
HTML
<nav>
<ul>
<li>Home</li>
<li>Lessons</li>
<ul>
<li>Lesson 1</li>
<li>Lesson 2</li>
</ul>
<li>Dictionary</li>
<ul>
<li>Phrases</li>
<li>Onomatopoeia</li>
</ul>
<li>Sentences</li>
<ul>
<li>Beginner</li>
<li>Intermediate</li>
<li>Advanced</li>
</ul>
</ul>
</nav>
CSS
nav {
width: 180px;
margin-top: 15px;
}
nav ul {
list-style: none;
margin: 0;
padding: 0;
}
nav ul li {
position: relative;
}
nav a {
color: 101010;
padding: 12px 0px;
display: block;
text-decoration: none;
transition:background 1s;
-moz-transition:background 1s;
-webkit-transition:background 1s;
-o-transition:background 1s;
font-family:tahoma;
font-size:13px;
text-transform:uppercase;
padding-left:20px;
}
nav a:hover {
background: #ececec;
}
nav ul ul {
display: none;
}
nav ul li:hover ul {
display: block;
}
Your nesting is off. Instead of:
<li>Lessons</li>
<ul>
<li>Lesson 1</li>
<li>Lesson 2</li>
</ul>
You need to include your submenu ul within the parent li that gets hovered over:
<li>
Lessons
<ul>
<li>Lesson 1</li>
<li>Lesson 2</li>
</ul>
</li>

CSS Drop Down menus won't align with parent Menus

Having trouble getting the drop-down menus to be directly aligned with the parent ones - at the moment they always fall from the center of the top one, see image.
My code:
body {
background: url('body-bkg.jpg');
background-repeat: no-repeat;
background-position: center top;
}
#navMenu {
margin: 0;
padding: 0;
text-align: center;
}
/*controls top parent box in navigation bar*/
#navMenu ul {
margin: 0;
padding: 0;
line-height: 30px;
display: inline-block;
}
/*controls top parent box in navigation bar*/
#navMenu li {
margin: 0;
padding: 0;
list-style: none;
position: relative;
background-color: hsla(0, 9%, 202%, 0.7);
float: left;
}
#navMenu ul li {
position: relative;
}
/*controls link text parent and children boxes in navigation bar*/
#navMenu ul li a {
text-decoration: none;
height: 30px;
width: 150px;
display: block;
color: #2e1c1c;
border: 1px solid #000;
}
/*controls children boxes in navigation bar*/
#navMenu ul ul {
position: absolute;
visibility: hidden;
top: 31px;
}
/*controls children boxes in navigation bar when hovered on parent box*/
#navMenu ul li:hover ul {
visibility: visible;
}
/*controls parent box when hovered on children box*/
#navMenu li:hover {
background: #387cf7;
}
/*controls child box when hovered on child box*/
#navMenu ul li:hover ul li a:hover {
background: white;
}
<div id="navMenu">
<ul>
<li>Destinations
<ul>
<li>Asia </li>
<li>Africa </li>
<li>Europe </li>
<li>North America </li>
<li>South America </li>
<li>Antartica </li>
</ul>
</li>
<li>Holiday Types
<ul>
<li>Short Breaks </li>
<li>Beaches </li>
<li>Adventure </li>
<li>Walking </li>
<li>Continents </li>
<li>Safari </li>
<li>Cruise </li>
<li>Family </li>
<li>Ultimate </li>
</ul>
</li>
<li>When to go
<ul>
<li>Winter </li>
<li>Spring </li>
<li>Summer </li>
<li>Autumn </li>
</ul>
</li>
<li>Corporate </li>
<li>Special Offers </li>
<li>About Us </li>
<li>Blog </li>
<li>Contact </li>
</ul>
</div>
This solution may work for you:
Demo Fiddle
I see you're using visibility:hidden a lot, but In situations like this I find display: none to be easier to work with.
CSS:
#navMenu ul ul {
// current styles
left: 0px;
}

CSS Submenu as Wide as Its Parent

I am making a horizontal menu and sub menu (level 2) inside a wrapper. Please imagine this menu is on the top right of the page / wrapper. The problem is, since the sub menu is also horizontal it can (will) be too wide and will overflow outside the wrapper.
Here it is:
http://jsfiddle.net/5DWer/
There is "menu-wrapper" there, but it is not the wrapper I was referring above.
The wrapper is right after "Tab 3" so "Tab 3 sub 2" is outside the wrapper.
I think the solution is to have the second level menu to start at the same point below the first level so it will never flow outside the wrapper (assuming the first level is wide enough). In the fiddle link: "tab 3 sub 1" starts right below "tab 1". I can't just use margin-left or left because I don't know under which tab the sub menu will start.
Is this possible or is there other solution? If possible in pure CSS, but I'll take Javascript if it isn't.
Thanks in advance :)
Thanks for the explanation. Sorry, here is the code:
<div class="menu-wrapper">
<ul class="menu">
<li>tab 1</li>
<li>tab 2</li>
<li>tab 3</li>
<ul>
<li>tab 3 sub 1</li>
<li>tab 3 sub 2</li>
</ul>
</ul>
</div>
and the CSS
.menu-wrapper {
width: 100%;
}
.menu {
max-width: 450px;
float: right;
}
.menu li a,
.menu li {
display: inline-block;
text-decoration: none;
}
.menu li:hover > ul {
display: block;
}
.menu li ul {
display: none;
width: 404px;
position: absolute;
}
.menu li li{
width: 200px;
margin: 0;
}
.menu li ul ul {
top: 100%;
left: 50%;
width: 200px;
}
.menu ul li:hover > ul {
border-left: 0;
display: block;
}
.menu li ul li a {
display: block;
padding: 8px 10px;
padding: 0.571428571rem 0.714285714rem;
width: 180px;
width: 12.85714286rem;
white-space: normal;
}
here is the solution to your problem: (I added a 3rd subtab to show it works)
http://jsfiddle.net/5DWer/3/
However, like I mentioned in the fiddle as comment:
You have to manually specify the width of the second-level ul.
Also, you have to nest your second level properly, like this:
<div class="menu-wrapper">
<ul class="menu">
<li>tab 1</li>
<li>tab 2</li>
<li>tab 3
<ul>
<li>tab 3 sub 1</li>
<li>tab 3 sub 2</li>
</ul>
</li>
</ul>
</div>
and not outside the li.
For reference (jsfiddle code):
HTML:
<div class="menu-wrapper">
<ul class="menu">
<li>tab 1</li>
<li>tab 2</li>
<li>tab 3
<ul>
<li>tab 3 sub 1</li>
<li>tab 3 sub 2</li>
<li>tab 3 sub 3</li>
</ul>
</li>
</ul>
</div>
And CSS:
.menu-wrapper {
width: 100%;
}
.menu {
max-width: 450px;
float: right;
}
.menu li {
display: inline-block;
text-decoration: none;
font-family: Arial, sans-serif;
background-color: yellow;
width: 50px;
height: 20px;
text-align: center;
}
.menu li ul {
display: none;
width: 500px; /* caveat : you have to specify the width manually */
margin-top: 10px;
}
.menu li:hover ul {
display: block;
float: right;
}
.menu li ul li {
float: right;
background-color: orange;
height: 100%;
}
.menu li ul li a {
padding: 8px 10px;
padding: 0.571428571rem 0.714285714rem;
width: 180px;
width: 12.85714286rem;
white-space: normal;
}
Looking at your code, it seems to be operating as expected. It seems to me, from what I can see (given the float:right for example) that this is more of a ui/design problem than a code problem. If not, maybe you can provide further details on your actual design so I can provide a css solution.

Add space between <li> elements

I have a nav-menu on which it seems that I can't add a space (margin: 3px;) between the <li> elements.
You can see the HTML and CSS code on this jsfiddle or below.
You will see that I've added a border-bottom: 2px solid #fff; to the #access li to simulate the space between elements, but that is not going to work because under the nav-menu I will have a bunch of different colors. If I add margin-button: 2px it doesn't work.
This is the HTML:
<nav id="access" role="navigation">
<div class="menu-header-menu-container">
<ul id="menu-header-menu" class="menu">
<li id="menu-item-41" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-41">
About Us
</li>
<li id="menu-item-35" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-35">
Services
</li>
<li id="menu-item-34" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-34">
Environmental Surface Cleaning
</li>
<li id="menu-item-33" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-33">
Regulations
</li>
<li id="menu-item-32" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-32">
Contact Us
</li>
</ul>
</div>
This is the CSS:
#access {
background: #0f84e8; /* Show a solid color for older browsers */
display: block;
margin: 0 auto 6px 55px;
position: absolute;
top: 100px;
z-index: 9999;
}
#access ul {
font-size: 13px;
list-style: none;
margin: 0 0 0 -0.8125em;
padding-left: 0;
}
#access li {
position: relative;
padding-left: 11px;
}
#access a {
border-bottom: 2px solid #fff;
color: #eee;
display: block;
line-height: 3.333em;
padding: 0 10px 0 20px;
text-decoration: none;
}
#access li:hover > a,
#access ul ul :hover > a,
#access a:focus {
background: #efefef;
}
#access li:hover > a,
#access a:focus {
background: #f9f9f9; /* Show a solid color for older browsers */
background: -moz-linear-gradient(#f9f9f9, #e5e5e5);
background: -o-linear-gradient(#f9f9f9, #e5e5e5);
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#f9f9f9), to(#e5e5e5)); /* Older webkit syntax */
background: -webkit-linear-gradient(#f9f9f9, #e5e5e5);
color: #373737;
}
#access ul li:hover > ul {
display: block;
}
UPDATE 2021
My original answer was from 2012 when many of the Level 3 CSS Selectors did not exist. To achieve this we would need JS or other explicit CSS styles/classes to achieve it. As #AlphaX has pointed out the best solution now is simply
li.menu-item:not(:last-child) {
margin-bottom: 3px;
}
OLD ANSWER
add:
margin: 0 0 3px 0;
to your #access li and move
background: #0f84e8; /* Show a solid color for older browsers */
to the #access a and take out the border-bottom. Then it will work
Here: http://jsfiddle.net/bpmKW/4/
You can use the margin property:
li.menu-item {
margin:0 0 10px 0;
}
Demo: http://jsfiddle.net/UAXyd/
There is a powerful feature of flex that allows for specifying space between every child without having to reference the "last-child" through gap. I find myself using more often than margin at this point:
ul {
display: flex;
flex-direction: column;
gap: 10px;
}
Example
li {
background: red;
}
ul {
background: silver;
display: flex;
flex-direction: column;
gap: 10px;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
Since you are asking for space between , I would add an override to the last item to get rid of the extra margin there:
li {
background: red;
margin-bottom: 40px;
}
li:last-child {
margin-bottom: 0px;
}
ul {
background: silver;
padding: 1px;
padding-left: 40px;
}
<ul>
<li>Item 1</li>
<li>Item 1</li>
<li>Item 1</li>
<li>Item 1</li>
<li>Item 1</li>
</ul>
The result of it might not be visual at all times, because of margin-collapsing and stuff... in the example snippets I've included, I've added a small 1px padding to the ul-element to prevent the collapsing. Try removing the li:last-child-rule, and you'll see that the last item now extends the size of the ul-element.
Most answers here are not correct as they would add bottom space to the last <li> as well, so they are not adding space ONLY in between <li> !
The most accurate and efficient solution is the following:
li.menu-item:not(:last-child) {
margin-bottom: 3px;
}
Explanation:
by using :not(:last-child) the style will be applie to all items (li.menu-item) but the last one.
Simple and fast. Just put css into ul element (the 'gap' property defines space between li elements):
display: flex;
align-items: flex-start;
flex-direction: column;
gap: 40px;
#access a {
border-bottom: 2px solid #fff;
color: #eee;
display: block;
line-height: 3.333em;
padding: 0 10px 0 20px;
text-decoration: none;
}
I see that you had used line-height but you gave it to <a> tag instead of <ul>
Try this:
#access ul {line-height:3.333em;}
You wouldn't need to play with margins then.
I just want to say guys:
Only Play With Margin
It is a lot easier to add space between <li> if you play with margin.

Resources