David
David

Reputation: 68

How to keep nested <li> from expanding parent <li> width?

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

Answers (2)

Stickers
Stickers

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

Obsidian Age
Obsidian Age

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

Related Questions