More pure CSS menus

two-line pure CSS menus

See it in action

In an ongoing effort to squeeze the most flexibility out of nested-list navigation menus, I developed this two-line version. Unlike the traditional OS-style dropdown menus, this one sacrifices horizontal space to save on vertical space, which is usually preferable in a small website. The menus can easily be aligned to the left or right instead of to the center.

Our HTML uses several nested unordered lists, with the top level given a unique ID (or class, if you prefer). This is basically identical to my previous pure CSS menus, and intentionally so–by separating style from structure and content, our design retains maximum flexibility.

<ul id="nav">
    <li><a href="#">Menu 1</a>
        <ul>
            <li><a href="#">Submenu 1-1</a></li>
            <li><a href="#">Submenu 1-2</a></li>
            <li><a href="#">Submenu 1-3</a></li>
            <li><a href="#">Submenu 1-4</a></li>
        </ul>
    </li><li><a href="#">Menu 2</a>
    <!-- etc. -->
</ul>

Let’s start with a few universal styles for the hyperlinks:

#nav a {
    display: block;
    color: black;
    text-decoration: none;
}
#nav li:hover > a {
    color: white;
    text-decoration: underline;
}

And then the top-level menu:

#nav {
    position: relative;
    background: #77f;
    height: 1.6em;
    text-align: center;
    white-space: nowrap;
    list-style: none;
    font-family: sans-serif;
    margin-bottom: 2em;
}

Significant elements:

  • The top-level menu must be relatively positioned because the sub-menus will be absolutely positioned later.
  • Setting white-space: nowrap keeps everything on a single line, even if that means it must scroll horizontally. Letting it wrap to a new line defeats the design, so keep your menu items brief.
  • The margin-bottom has to be big enough to accomodate the second line of sub-menus.

We now need to keep all the list items on a single line, but we can’t float them this time. Enter display: inline-block, with a few hacks to accomodate IE7 (which doesn’t support that):

#nav > li {
    display: inline-block;
    *display: inline; zoom: 1; *height: 1.6em; /* ie7 */
    line-height: 1.0em;
    padding: 0.3em 0.5em;
}

The asterisk is a well-documented trick to implement styles only for IE7 and IE6 without building a second conditional stylesheet. In this case, since those browsers don’t understand inline-block, we set the display to “inline” and add zoom: 1 to force hasLayout (block-like rendering) in IE. Specifying the height completes the trick — otherwise, in this case, the mouse would move off the bottom of the list element as you moved the cursor to the second line and the submenu would disappear before you got there.

On to the submenus. Obviously we want to hide them by default:

#nav > li > ul {
    display: none;
}

and display them only when their parent list item is hovered over:

#nav > li:hover > ul {
    display: block;
    position: absolute;
    left: 0;
    width: 100%;
    height: 1.6em;
    background: #aaf;
    list-style: none;
    top: 1.6em;
    height: 1.6em;
    text-align: center;
    white-space: nowrap;
}

As mentioned before, this row needs to be absolutely positioned to the left and just below the height of the top menu–at least, if you want the top menu to be centered.  Most of the other styles mirror those of the parent menu; adjust as desired.

Finally, the styles for the sub-menu list items, which (in this case) mirror the top menu exactly. We could probably have just combined those two style sets to eliminate redundancy, but it’s likely you’ll want to alter the styles for the sub-menus in practice — give it a smaller font, perhaps, or something else to distinguish it from the top menu further:

#nav > li > ul > li {
    display: inline-block;
    *display: inline; zoom: 1; *height: 1.6em; /* ie7 */
    line-height: 1.0em;
    padding: 0.3em 0.5em;
}

http://jsfiddle.net/mblase75/buJAj/

Leave a Reply

Your email address will not be published. Required fields are marked *

*