Horizontal menus and automatic widths
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;
}
#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 (See the W3C visual formatting module for non-replaced inline elements). 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 (See the W3C visual formatting module for non-replaced block elements).
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;
}
#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;
}
#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 (something I keep forgetting), 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;
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>
<li>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.
Drop me a line
Got any questions? Get in touch via the contact form or email me @ helen@alternategateways.com.
