Skip to main content

Horizontal menus and automatic widths

Submitted by helen on Friday, October 16, 2009 - 22:58; Modified on Thursday, August 18, 2016 - 11:10

This tutorial explains how to create a horizontal menu with list items that are the same width as the text they contain. In other words: a horizontal menu that contains list items that do not have a definite width, and contract or expand to fit their contents. If you're looking for information on how to create menus whose list items do have definite widths, visit Horizontal menus and list items with definite widths.

A basic menu with no padding

Here we will construct a basic menu without using any set widths or heights, and without applying any padding to our list items.

Example

CSS Code:


#horizMenu1 {
	list-style-type:none;
	margin:0;
	padding:0;
	background-color:#69C;
	color:#fff;
}

#horizMenu1 li {
	display:inline; 
	background-color:#66C;
	margin:0 6px 0 0;
}

(X)HTML Code:


<ul id="horizMenu1">
	<li>Up</li>
	<li>Down</li>
	<li>Charm</li>
	<li>Strange</li>
	<li>Top</li>
	<li>Bottom</li>
</ul>

Result:

Here is our finished product. As you can see, our menu items are only as big as their contents.

  • Up
  • Down
  • Charm
  • Strange
  • Top
  • Bottom

The six flavours of elementary particles known as quarks.

Explanation

The display:inline on the list items converts them to inline elements, which "shrink-wrap" to fit their contents. We then add a slight right margin to space the items out, ensuring they are easy to read, and not cramped.

Add Padding

We run into some issues when we want to add padding to our list items, because inline-level elements don't define what the content area of an line-box is. This causes problems for the block-level parent as it calculates its height based on the topmost line box and the bottom of the bottommost line box.

As you can see from below, the resultant effect is that the top and bottom padding end up being ignored by the containing element; they are being rendered, but the ul isn't aware of them.

What goes wrong

CSS Code:


#horizMenu2 {
	list-style-type:none;
	margin:0;
	padding:0;
	background-color:#69C; 
    color:#fff;
}

#horizMenu2 li {
	display:inline; 
	background-color:#66C;
	margin:0 6px 0 0; 
	padding:8px;
}

(X)HTML Code:


<ul id="horizMenu2">
	<li>Up</li>
	<li>Down</li>
	<li>Charm</li>
	<li>Strange</li>
	<li>Top</li>
	<li>Bottom</li>
</ul>

Result:

  • Up
  • Down
  • Charm
  • Strange
  • Top
  • Bottom

The fix

To overcome this, there are two things we can do: we can push the list items into the menu, by giving the menu a top and bottom padding or we can remove the display:inline, so our list items revert back to block elements. I know, it's kind of like we're going back on ourselves...

Giving our menu a top and bottom padding

This method is rather tenuous because there's no strict rule for adding the padding to the ul — it's really a matter of adding enough padding until the list items fit —and you will need to adjust the padding should you decide to increase or decrease the font size.

The reason I don't suggest giving the ul a definite height is because this doesn't work correctly in all browsers, due to the missing top and bottom padding and you end up with a ul that's too long in some browsers and too short in others. Adding extra padding to the ul doesn't cause as much grief — I know, this is just as much of a hack as giving the ul a definite height, and I wouldn't advocate either method, to be honest, but it's good to see how this stuff works.

CSS Code:


#horizMenu3 {
	list-style-type:none;
	margin:0;
	padding:0;
	background-color:#69C;
	padding:6px 0;
    color:#fff;
}

#horizMenu3 li {
	display:inline; 
	background-color:#66C;
	margin:0 6px 0 0; 
	padding:7px;
}

(X)HTML Code:


<ul id="horizMenu3">
	<li>Up</li>
	<li>Down</li>
	<li>Charm</li>
	<li>Strange</li>
	<li>Top</li>
	<li>Bottom</li>
</ul>

Result:

  • Up
  • Down
  • Charm
  • Strange
  • Top
  • Bottom

Here, we're giving our menu a top padding, to push the list items down into the menu, and we're giving it a bottom padding to make it seem as if the menu is accommodating the list items.

I personally wouldn't recommend this option as it's too unreliable. We're literally adding a figure in for the padding which relies on the size of the list item's font, which is never a good idea, as font size can — and should be allowed to — change.

Leaving the list items as block elements

List items are block elements, by default, with an added "marker" box for the bullet points. If we leave them as they are and not modify their display, we can add add padding to them and not bother with set heights on the parent.

CSS Code:


#horizMenu4 {
	list-style-type:none;
	margin:0;
	padding:0;
	background-color:#69C; 
    color:#fff;
	height:100%; /* For IE 6 */
	overflow:auto;
}

#horizMenu4 li {
	width:auto;
	float:left;
	background-color:#66C;
	margin:0 6px 0 0; 
	padding:8px;
}

(X)HTML Code:


<ul id="horizMenu4>
	<li>Up</li>
	<li>Down</li>
	<li>Charm</li>
	<li>Strange</li>
	<li>Top</li>
	<ligt;Bottom</li>
</ul>

Result:

  • Up
  • Down
  • Charm
  • Strange
  • Top
  • Bottom

Conclusion

The best approach for creating list items with automatic widths depends on what you want to accomplish. If having padded list items is your top priority, then your best approach is to keep your list items as block items. because that way, you're leaving the calculations of the menu's height to the browser; you don't have add any shaky padding values that may vary depending on which browser you are using. However, if your goal is to align your list items, while keeping their widths automatic, then the inline approach is the best as you can simply apply text-align to your ul, whereas aligning block-level list-items is more difficult.