Reputation: 68
My CMS handles dropdown menus by nesting them like:
body {
text-align: center;
}
ul.nav {
margin: 0;
padding: 0;
display: inline-block;
list-style-type: none;
}
li.top-item {
margin: 0;
padding: 0;
float: left;
padding: .5em;
}
ul.dropdown-list {
margin: 0 0 -8em;
padding: 0;
display: none;
list-style-type: none;
background: #eee;
position: relative;
}
a.dropdown:hover+ul.dropdown-list {
display: block;
}
<ul class="nav">
<li class="top-item"><a href="#">home</a></li>
<li class="top-item"><a href="#" class="dropdown">dropdown</a>
<ul class="dropdown-list">
<li class="dropdown-item">item 1</li>
<li class="dropdown-item">item 2 expands parent :(</li>
<li class="dropdown-item">item 3</li>
</ul>
</li>
<li class="top-item"><a href="#">about</a></li>
</ul>
<p>Lorem ipsum and such...</p>
The problem is that if the child link has a longer name/title than it's parent, hovering over the parent makes the parent expand to fit the width of the widest child. Example in this link: https://codepen.io/ivorytux/pen/PObemb
What's a good way around this where the top-level menu would stay at a consistent width and only have the drop-down menu fit the width of it's links?
Upvotes: 0
Views: 548
Reputation: 78676
You should set the top item to relative position:
li.top-item {
position: relative;
...
}
And the sub menu item to absolute position:
ul.dropdown-list {
position: absolute;
...
}
In addition to that, you can also set:
ul.dropdown-list {
position: absolute;
white-space: nowrap; /* no wrapping */
left: 50%; /* horizontal center */
transform: translateX(-50%); /* horizontal center */
}
Lastly, you need to update the hover object to:
li.top-item:hover ul.dropdown-list {
display: block;
}
As in your example in the question you are not be able to select the sub menu.
Full code snippet:
body {
text-align: center;
}
ul.nav {
margin: 0;
padding: 0;
display: inline-block;
list-style-type: none;
}
li.top-item {
margin: 0;
padding: 0;
float: left;
padding: 0.5em;
position: relative;
}
ul.dropdown-list {
margin: 0 0 -8em;
padding: 0;
display: none;
list-style-type: none;
background: #eee;
position: absolute;
white-space: nowrap;
left: 50%;
transform: translateX(-50%);
}
li.top-item:hover ul.dropdown-list {
display: block;
}
<ul class="nav">
<li class="top-item"><a href="#">home</a></li>
<li class="top-item"><a href="#" class="dropdown">dropdown</a>
<ul class="dropdown-list">
<li class="dropdown-item">item 1</li>
<li class="dropdown-item">item 2 this is a long item</li>
<li class="dropdown-item">item 3</li>
</ul>
</li>
<li class="top-item"><a href="#">about</a></li>
</ul>
<p>Lorem ipsum and such...</p>
Upvotes: 2
Reputation: 42304
What I would recommend is to give your hidden ul
element position: absolute
to take it out of the flow. This will prevent it from messing up the parent's width, but will 'offset' it slightly. This can be counteracted with a negative margin-left
. I've gone with margin-left: 45px
in this example, but you may need to play around with that. You can also offset the height of the dropdown with top
if need be.
body {
text-align: center;
}
ul.nav {
margin: 0;
padding: 0;
display: inline-block;
list-style-type: none;
}
li.top-item {
margin: 0;
padding: 0;
float: left;
padding: 0.5em;
}
ul.dropdown-list {
margin: 0 0 -8em;
padding: 0;
display: none;
list-style-type: none;
background: #eee;
position: relative;
}
a.dropdown:hover+ul.dropdown-list {
display: block;
position: absolute;
margin-left: -45px;
/* top: 90px; */
}
<ul class="nav">
<li class="top-item"><a href="#">home</a></li>
<li class="top-item"><a href="#" class="dropdown">dropdown</a>
<ul class="dropdown-list">
<li class="dropdown-item">item 1</li>
<li class="dropdown-item">item 2 expands parent :(</li>
<li class="dropdown-item">item 3</li>
</ul>
</li>
<li class="top-item"><a href="#">about</a></li>
</ul>
<p>Lorem ipsum and such...</p>
Upvotes: 0