Menu example - Left and Right CSS Dropdown Menu

Introduction

Over the last couple of years there has been an increasing focus on Web page speed. Partly this is due to initiatives by Google and Yahoo, partly it is due to the explosive increase in web browsing on devices such as iPads and advanced cell phones (iPhone, Androids, etc).

Gradually, the focus on speed has also resulted in increased attention being devoted to more efficient CSS. Efficient HTML and CSS can help improve rendering speed significantly, not least on mobile devices with slower processors. I have done a lot of work to speed up web sites lately, and in the process I have noticed that menu systems is an area where there is a lot of inefficient CSS floating around. It turns out there is lots of room for improvements and that much code used in menus is relatively bad. The Nekkidblogger menus are based on simple HTML and very efficient and fast CSS.

Below is the HTML and CSS for a JavaScript free dropdown menu where the dropdown of the elements on the left-hand side flow to the right and the dropdowns on the right-hand side flow to the left.

Markup (HTML)

This is basically a standard unordered list (<ul><li>). I have highlighted the non-standard features. It has class="menu" and each of the sublevels (nested lists) have classes describing the level: level2, level3 and level4.

Usually lists used in menus are not styled with classes like this. However, doing it this way has some great advantages: It makes it easy to build a CSS menu with very few style rules; it allows for very efficient CSS; and provides (as a kind of bonus) convenient "hooks" (i.e. the "level" classes") for styling if one wants to style the dropdown levels differently from the top level.

 
<ul id="nekkidblogger">
<li><a href="#">Link 1</a>
    <ul class="level2">
    <li><a href="#">Link 1-1</a></li>
    <li><a href="#">Link 1-2</a>
       <ul class="level3">
         <li><a href="#">Link 1-2-1</a></li>
         <li><a href="#">Link 1-2-2</a>
            <ul class="level4">
              <li><a href="#">Link 1-2-2-1</a></li>
              <li><a href="#">Link 1-2-2-2</a></li>
            </ul></li></ul></li>
  </ul></li>
<li><a href="#">Link 2</a>
    <ul class="level2">
    <li><a href="#">Link 2-1</a></li>
    <li><a href="#">Link 2-2</a></li>
    <li><a href="#">Link 2-3</a></li>
  </ul></li>
<li><a href="#">Link 3</a>
    <ul class="level2">
    <li><a href="#">Link 3-1</a></li>
    <li><a href="#">Link 3-2</a></li>
  </ul></li>
<li><a href="#">Link 4</a>
    <ul class="level2">
    <li><a href="#">Link 4-1</a></li>
    <li><a href="#">Link 4-2</a>
       <ul class="level3 left">
         <li><a href="#">Link 4-2-1</a></li>
         <li><a href="#">Link 4-2-2</a>
            <ul class="level4 left">
              <li><a href="#">Link 4-2-2-1</a></li>
              <li><a href="#">Link 4-2-2-2</a></li>
            </ul></li></ul></li>
  </ul></li>
</ul>

CSS for the Nekkidblogger menu (with comments)

One of the keys to efficient CSS is to use the "cascade" as much as possible - to allow "child-elements" to inherit as much as possible from "parent" elements. So here I don't define selectors if I can avoid it and let inheritance take care of the styling. That is, I try to only style elements once, and then let inheritance take care of as much as I can.

Notice that the only thing I need to change in the markup (HTML) compared to the usual Nekkidblogger menu, is to add "left" as a class along with "level3" and "level4" for the rightmost link.

The structural rules are marked as "rules", while the presentational style rules are marked as "styles". The main rules for this version of the menu are the same as for the horizontal version of the Nekkidblogger menu, so I refer to that post for extended discussions of the basic CSS-rules. Here I focus on the extra CSS needed to make the right-most element of the menu pop out to the left while the rest of the menu moves to the right. But first the basic rules:

#nekkidblogger ul {padding:0;margin:0;} (Style 1)

This is useful for setting the context. If you use a CSS reset, you don't need this. Also, you may prefer simply ul {padding:0;margin:0;}. I use the more specific reset (for the "menu"-class only) because I also display unordered lists in many other ways (for instance above right) in this blog.

The Top level

#nekkidblogger li { list-style:none; position:relative; float:left;
    text-align:center; margin-right:5px; font: 10px verdana, 
    sans-serif; } (Rule 1)

This is the first rule of the menu. Here "list-style", "position" and "float" are necessary structual elements, while "text-align, "margin" and the rest are presentational. Note that I style the a-selector, not the <li>. The <li>-element adapts to its content - so we don't need to define a "width" here for example.

#nekkidblogger a { display: block; width: 10em; color: black; line-height: 30px; 
     text-decoration: none; background: rgb(255,255,0); /* Fallback */
     background: rgba(255,255,0, 0.8); border:1px solid #fff;
     margin: 0 -1px -1px 0; } (Style 2)

Here "display:block" is necessary to make the links display properly with the styling. This is a presentational rule.

#nekkidblogger :hover > a { background: rgb(255,255,204); /* Fallback */
        background: rgba(255,255,204, 0.8); color: #222; } (Style 3)

This is a presentational element only - we don't need to set different properties for the hover state. Here I style the whole path instead of just the hover (one usually uses simply "a:hover". I picked up and adapted this neat little trick from the excellent CSS experiments by Stu Nicolls.

What we have done so far (we have also "set the stage" for the lower levels):

Second and lower levels

The rest is purely structural - no presentational elements, as I simply let the lower levels of the menu inherit everything. However, I will show you how you can easily style the lower levels.

A. Style the boxes

The classes ".level2-.level(n)" provide "hooks" that you can easily use to format the lower levels.

We could, for instance, give a different style to level two and the lower levels - just style ".level2" and let the lower levels inherit. Or we could style each level separately. For example:

#nekkidblogger .level2 a { background:black; height: 25px; etc .. }
And/or, we could style the lower levels like so:
#nekkidblogger .level3 a { ... }
#nekkidblogger .level4 a { ... }

B. Position the boxes

The top level is horizontal. We want to drop the second level down vertically from it. We have defined the <li>'s to be relative, so now we position the dropdown (.level2) in relation to them:

.level2 { position:absolute; top:30px; left:0;  }  (Rule 2)

Here "left:0" is default in the good browsers, so we should not need to specify it, but as it for some reason is not so in IE (surprise?), we still must. 30px is the line-height - see Style 2.

The next two levels - level 3 and level 4 - we want to fly out to the right of level 2. 8 em is the width of the a-element (see Style 2). I add .08em to get the alignment correct (approximately 1px extra). So:

.level3,.level4 { position:absolute; top:0; left:10.08em; } (Rule 3)
.left { position:absolute; left:-10.08em; } (Rule 4)

For the "left" class, I don't need to define the "top"-property as it is defined for the 'level' class. Also note that in the markup I use "level3 left": if the order had been the opposite this CSS would not have worked; then I would have needed to give "left" higher specificity than "level3" and "level4".

C. Hide and then unhide when hover

.level2,.level3,.level4 {visibility:hidden} (Rule 5)

We need to hide all levels separately - if we let "hidden"-property be inherited, then the "visible"-property will be too. Note that if you want to add another level or two to the menu, all you need is to insert the correct classes in the HTML for the list and then add ".level5, .level6" in Rules 4 and 5. So adding N more levels, using the Nekkidblogger menu framework, does not add to the complexity of the CSS.

#nekkidblogger :hover > ul { visibility:visible; }(Rule 6)

Rule 5 makes the child elements of a <ul> visible when <li> is hovered (but only the child-elements, not the "grand-children"). (Note: If you really want to be radical, you can actually write Rule 5 like so: :hover > ul { visibility:visible; }. But that's neither safe nor sound - the hover pseudo-operator is a powerful beast.) And that's all.

Behold the sleek and efficient marvel of a menu:

Fixes for IE6

IE 6 does not support the CSS hover pseudoclass and has some other quite serious bugs as well. In order for the menu to run in IE 6 we therefore need a JavaScript to fix the hover and some CSS fixes.

The JS is called "gen_suckerfish_ie.js". It's a more general version of the "suckerfish_ie". The latter works only on hover-items in elements with "id=nav", whereas this version works on all hovered <li>'s.

Now the CSS fixes (ugly, but this is IE 6):

#nekkidblogger a:hover { background: #7B7B7B; color: yellow; }
#nekkidblogger ul li { vertical-align:bottom; } /* *ul li */
#nekkidblogger .level2 li, .level3 li, .level4 li { float:none; width:8.08em;  } 
#nekkidblogger li.sfhover ul ul,#nekkidblogger li.sfhover ul ul ul 
  { visibility: hidden; } 
#nekkidblogger li.sfhover ul,#nekkidblogger li li.sfhover ul,
  #nekkidblogger li li li.sfhover ul { visibility:visible; }

First, IE6 does not understand the child operator ">" (Style 3 and Rule 6). Second, it does not understand hover for anything but links. The second line takes care of a bug which otherwise results in gaps between vertical elements in the menu in IE6 ("the drop gap bug"). The third line tells IE6 not to float the dropdown li-elements. It also turns out IE6 need a width set explicitly on the LI element for the dropdown - without it the scrolling will not work on levels 3 and 4. The last two lines are rewrites of Rules 4 and 5 for the JS (which needs the DOM tree the old fashioned way).

The best way to use these styles are to place them in a conditional style sheet for IE6 only. If you look at the source code, you can see how I have done it for this page.

Final remarks

So, that's it. Six "structual" CSS-rules for a multi-level menu that drops both right and left, along with a little styling. The rules are not only few, but also simple, mostly very short, and computationally effective (good for fast page loading) with minimum use of descendant selectors.

If you examine this page with Google's Page Speed (using Firefox), and look at the use of efficient selectors, you will find that it has "0 very inefficient rules, 0 inefficient rules, and 2 potentially inefficient uses of :hover". The "potentially inefficient" rules are "#nekkidblogger :hover>ul" and "#nekkidblogger li:hover>a" (the latter shows the hover path).

If by comparison you run Page Speed on the Son of Suckerfish menu with three dropdowns, which is a very widely used menu, you will find that it has "7 very inefficient rules, 5 inefficient rules, and 5 potentially inefficient uses of :hover". So, there is a difference. And if Google's Page Speed is worth anything, and page speed matters, it may well be a difference that matters.

The Nekkidblogger menu has been extensively tested, and works in recent versions of Chrome, Firefox, Opera, and Safari, as well as Internet Explorer 7 and newer. For IE 6 it needs the fixes described above. It probably does not work in versions of IE prior to IE6 (not tested, as they hardly exist anymore).

PS: See also the standard horizontal dropdown menu, the barebones Nekkidblogger menu, and the vertical Nekkidblogger menu.

Copyright

I spend lots of time on development and posting. Therefore I kindly ask that you respect my copyright.

1. If you are using this on a personal web site then please retain the copyright comment in the stylesheet. A donation to Nekkidblogger is requested.

2. If you are using this on a commercial web site, or as a paying job for a client, then please email me asking for permission - peter{at}nekkidblogger.com. A donation to support 'Nekkidblogger' is required. USD 25 per client seems a fair suggestion.

3. If you are having problems integrating it into your website then I now offer a service to fault find and correct any errors that you may have introduced. Please email me for more information.

Terms and Conditions

This menu can be used subject to the following terms and conditions:

  • 1.If you wish to use this menu in your website(s) you can do so.
  • 2.You may NOT place this menu on another site for others to download.
  • 3.You may NOT redistrubute or resell this menu.
  • 4.Users agree not to remove or edit the credit notice within the stylesheet, or claim that this menu is their own.

Files

Pay me $ 10 with Paypal and send me a mail about it, and I will send you the HTML, CSS, and JS in a zipped file. Send $100 and I'll give you 2 hours of support by email as well.

Hire me?

If you need assistance, you can hire me set up a site for you, write or rewrite HTML / CSS, make your site responsive, or modify an existing site.

Please support

Blogging and web design is my living. It takes time to develop, test and write up.

So a donation would be very welcome, especially if you are going to use the code or have learned something reading this.

Nekkidblogger needs
your support! Thanks!!


Back to the post at nekkidblogger.com

See also Suckerfish revisited - CSS/HTML dropdown menu: Barebones