Drop-Down Menus, Horizontal Style

Anyone who has created drop-down menus will be familiar with the large quantities of scripting such menus typically require. But, using structured HTML  and simple CSS, it is possible to create visually appealing drop-downs that are easy to edit and update, and that work across a multitude of browsers, including Internet Explorer. Better still, for code-wary designers, no JavaScript is required! (Actually, a tiny bit of JavaScript is needed, but it’s not what you think.)

Article Continues Below

Here’s a sneak preview of the menu in action.

Creating the menu#section2

The first and most important part of creating our menu is the menu structure itself. The best way to do this is to build an unordered list, with each sub-menu appearing as a list within its parent list item. Sound complicated? It’s actually very straightforward:

<ul> 
  <li><a href="#">Home</a></li> 
  <li><a href="#">About</a> 
      <ul> 
      <li><a href="#">History</a></li> 
      <li><a href="#">Team</a></li> 
      <li><a href="#">Offices</a></li> 
      </ul> 
    </li> 
  <li><a href="#">Services</a> 
      <ul> 
      <li><a href="#">Web Design</a></li> 
      <li><a href="#">Internet 
            Marketing</a></li> 
      <li><a href="#">Hosting</a></li> 
      <li><a href="#">Domain Names</a></li> 
      <li><a href="#">Broadband</a></li> 
      </ul> 
    </li>
  <li><a href="#">Contact Us</a> 
      <ul> 
      <li><a href="#">United Kingdom</a></li> 
      <li><a href="#">France</a></li> 
      <li><a href="#">USA</a></li> 
      <li><a href="#">Australia</a></li> 
      </ul> 
    </li> 
  </ul>

That’s it: some simple HTML that is both accessible and easy to edit.

Visually appealing?#section3

If you have previewed the menu above, you’ll see a pretty boring list of items. And I promised you it would be visually appealing! Let’s add some style.

The first step is to remove the indents and bullets from the unordered list and define the width of our menu items.

ul {
 margin: 0;
 padding: 0;
 list-style: none;
 width: 150px;
 }

Next, we need to position our list items. Fortunately, these will stack vertically by default, which is what we require. However, we must set the position as relative, because we will need to position the sub-menus absolutely within them.

ul li {
 position: relative;
 }

Next step is the sub-menus. We want each sub-menu to appear to the right of its parent menu item when that item is hovered over.

li ul {
 position: absolute;
 left: 149px;
 top: 0;
 display: none;
 }

Using the “left” and “top” attributes, we can absolutely position each sub-menu within its parent menu item. You will notice I have set the “left” property to 149px (1px less than the width of the menu items), which allows the sub-menus to overlap the main menu and not produce a double border. (You’ll see what I mean later.)

We have also set display to “none,” as we don’t want the sub-menus to be visible by default.

So now we have the framework in place, but it’s still looking a bit plain. Let’s style those links.

ul li a {
 display: block;
 text-decoration: none;
 color: #777;
 background: #fff;
 padding: 5px;
 border: 1px solid #ccc;
 border-bottom: 0;
 }

I have styled the links to my taste, but they can be changed to your preference, as you wish. It is important to set display to “block,” as we want each link to take up all the available space of its containing list item.

So things are looking a little better, although users of Internet Explorer for Windows may disagree. Unfortunately, IE Win interprets the line breaks between our nicely formatted HTML list items as white space, so you will notice that the menu items don’t stack up neatly in that browser. However, there is a way around IE’s bugs:

/* Fix IE. Hide from IE Mac */
* html ul li { float: left; }
* html ul li a { height: 1%; }
/* End */

We can apply the Holly Hack above, which hides these rules from all browsers but IE Win. Perfect. You will notice the height: 1% rule that has also been added. Unfortunately (again!) the float fix uncovers another IE bug, which requires a height value to make the links display as block-level elements.

You will also notice the need to close the menu, which can be done by adding the missing border to the bottom of the list. So, the ul rule becomes:

ul {
 margin: 0;
 padding: 0;
 list-style: none;
 width: 150px;
 border-bottom: 1px solid #ccc;
 }

With some luck, everyone should now be able to see the unfunctional menu.

Making it work#section4

Now the fun bit. We need to make those sub-menus appear when we hover over the menu items.

li:hover ul { display: block; }

Voila…here’s the bare bones menu in action.

“Woo hoo! It works!” I hear 1% of you shout. “Awesome!”

OK, OK, so that darn IE/Win has to ruin everything and not do as it’s told. IE/Win only allows the :hover pseudo-class to be applied to a link — so the li:hover that makes the sub-menus appear means nothing to IE.

A tiny jot of JavaScript is required to kick IE back into action (line wraps marked »Ed.):

startList = function() {
if (document.all&&document;.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navroot.childnodes.length; i++)="" {="" node="navRoot.childNodes<i">;
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
  }
  node.onmouseout=function() {
  this.className=this.className.replace»
 (" over", "");
   }
   }
  }
 }
}
window.onload=startList;
</navroot.childnodes.length;>

Great thanks and appreciation is due here to Patrick Griffiths and Dan Webb, who introduced this trickery in a previous ALA article, Suckerfish Dropdowns. Thanks, guys!

So, the hover rule now becomes:

li:hover ul, li.over ul { 
 display: block; }

Additionally, we also need to associate the JavaScript with our main ul, which becomes:


Hopefully, with the above tweaks in place, everyone should be able to see a simple version of the menu in action.

IE5.01 Jumping Menu Bug#section5

Anyone using IE5.01 on Windows will notice that the menu jumps around when you hover over some of its items. The problem is easily fixed by modifying our previous hacks as follows:

/* Fix IE. Hide from IE Mac */
* html ul li { float: left; height: 1%; }
* html ul li a { height: 1%; }
/* End */

Mystery IE6 Bug:#section6

During the development of this article, I uncovered a strange bug that I believe is only apparent in IE6. A background must be declared on the li a, else when a sub-menu stretches further (vertically) than the main menu itself, the links start to disappear before you have time to click them. Strange! Try it to see for yourself.

Making it your own#section7

That’s it! A standards-friendly method for creating visually appealing horizontal drop-down menus. All you have to do now is add some hover styles and make it your own. Just to give you a taste, here’s a prettier one I prepared earlier. Enjoy!

About the Author

Nick Rigby

Nick Rigby is a freelance web standards and accessibility developer for his company, Puretic. In between work he enjoys football, music, being creative, and writing the occasional article for nickrigby.com.

296 Reader Comments

  1. Hi,
    great example, it works on all the other browers but explorer. I keep getting an error on line 53 which is

    for (i=0; i<navRoot.childNodes.length; i++) {

    and the next line is

    node = navRoot.childNodes[i];

    please can anyone help
    i have explore ver 6

  2. I don;t get the hovering elements to work in the following case:
    Trying to use this menu with the body being a fixed size div with the following style applied.

    .content {OVERFLOW:auto;height:550px;PADDING: 0px 0px 5px 5px;}

    When I fix the height so a scroll bar appears, then the menu appears but disappears when mousing over….

    Don;t understand enough about DOM to know why this occurs (in firefox by the way, and same occurs with the Dutch naarvoren.nl menu – first post). Just thought i’d add my bit… otherwise excellent idea – thanks.

  3. Hi, I’ve spent some time learning and implementing this menu system into my site, and I like it very much. I didn’t want to get into heavy JScripts because I need to keep things simple. On Mozilla Firefox, it works great with 2 levels of sublist, but I am not sure how to setup the javascript to handle the second level of menus. It works with the first level but not the next. I tinkered a littlebit, but I don’t know what to add. Is there a simple bit of code I could add to make it work?

    Also, It works great (not in IE6) with the 2nd level of drop downs, but I have not been able to have much sucess over a third level (it will only hide the third level until you reveal the second level, at which time it reveals the third level. I’m referring to it as Top level, First level (as deep as the article shows you how to create), 2nd level (one more down – this works fine), 3rd level (doesn’t work – when u mouse over a 1st level list to show a 2nd level list, any third level lists appear when the 2nd level list does).

    Thanks so much!

    Kindari

  4. Hi,
    I’m a novice at html but would really like to use this menu. Where on your html page do you place ul {
    margin: 0;
    padding: 0;
    list-style: none;
    width: 150px;}
    etc?
    Many thanks

  5. The CSS code goes either in:


    your title


    or in an external .css file, which is just a text document containing the CSS code.

  6. A simple and usefull article!
    I made the menu on my own and it works without any problem.

    Now I want to integrate the menu in the left frame of my homepage. How can I make it overlap in the main frame?
    If it doesn’t the menu would take to much space. Is there a simple possibility to realize something like that?

  7. Hi,

    I love this solution and am using a combo of it and the Suckerfish code to make my menus work. There’s one thing missing I would love some help with.

    I want to have my top level item (i.e. About Us) remain highlighted in the hover color while the user is over the sub-menu (i.e. company news, our offices, etc)…how can I make this happen?

    Thanks,
    Sara

  8. Im very new to Javascript, where do I put it in the code of the whole site? will someone email me with what the final product of this should be?

  9. For a fleeting split-second I was able to see your intended formatting, but it disappeared and reverted to the original bland first effort. Was this intended or has something gone wrong somewhere?

  10. This was an extremely helpful article, but I am having a couple of problems with it. (additional information at bottom of comment)

    1.Using an Iframe with this script, as you would see in my code, My levels stop the second I pass into that Iframe, is there a way I can stop that from happening?

    2.How can I make this menu support multiple levels, at the moment all we need is two subs.

    ADDITIONAL INFORMATION
    Please e-mail me the answers if possible.
    E-mail — Zlord1@gmail.com
    you do need to go to the specified url in order to understand most of my questions.

  11. In trying to keep up to date with standards I tried this in XHTML 1.1 only to find that nested lists don’t validate with the W3C validator.
    How can I get it to work?

  12. I’m in the process of using this technique on a site that doesn’t have a fixed width or fixed position design. How can this be acheived? For instance I have a navigation element that is wrapped in a container

    tag that is centered on the screen. How can you use this technique when you use position:absolute for the second ul?
  13. I tried having more that just two layers like the example, but when I hovered over the first layer it showed the 2nd and 3rd layer. How do I hide it until I hover over the second layer?

  14. Why not simply use a:hover to open the sublists, to work around the IE bug without using JavaScript?

  15. I does not work with this code made by youre article:

    <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>

    <html>
    <head>
    <SCRIPT LANGUAGE=”JavaScript “>
    startList = function() {
    if (document.all&&document.getElementById) {
    navRoot = document.getElementById(”nav”);
    for (i=0; i<navRoot.childNodes.length; i++) {
    node = navRoot.childNodes[i];
    if (node.nodeName==”LI”) {
    node.onmouseover=function() {
    this.className+=” over”;
    }
    node.onmouseout=function() {
    this.className=this.className.replace»
    (” over”, “”);
    }
    }
    }
    }
    }
    window.onload=startList;
    </script>
    <style type=”text/css”>

    ul {
    margin: 0;
    padding: 0;
    list-style: none;
    width: 150px;
    border-bottom: 1px dotted #000000;
    }

    ul li {
    position: relative;
    }

    li ul {
    position: absolute;
    left: 149px;
    top: 0;
    display: none;
    }

    ul li a {
    display: block;
    text-decoration: none;
    color: #000000;
    background: #00ccff;
    padding: 5px;
    border: 1px dotted #000000;
    border-bottom: 0;
    }

    /* Fix IE. Hide from IE Mac */
    * html ul li { float: left; }
    * html ul li a { height: 1%; }
    /* End */

    li:hover ul, li.hover ul {
    display: block; }

    <ul id=”nav”>

    </style>

    </head>

    <body>

    <ul>
    <li><a href=”#”>Home</a></li>
    <li><a href=”#”>About</a>
    <ul>
    <li><a href=”#”>History</a></li>
    <li><a href=”#”>Team</a></li>
    <li><a href=”#”>Offices</a></li>
    </ul>
    </li>
    <li><a href=”#”>Services</a>
    <ul>
    <li><a href=”#”>Web Design</a></li>
    <li><a href=”#”>Internet
    Marketing</a></li>
    <li><a href=”#”>Hosting</a></li>
    <li><a href=”#”>Domain Names</a></li>
    <li><a href=”#”>Broadband</a></li>
    </ul>
    </li>
    <li><a href=”#”>Contact Us</a>
    <ul>
    <li><a href=”#”>United Kingdom</a></li>
    <li><a href=”#”>France</a></li>
    <li><a href=”#”>USA</a></li>
    <li><a href=”#”>Australia</a></li>
    </ul>
    </li>
    </ul>

    </body>
    </html>

    What am i doin wrong?

    Greetz

    Rivers

  16. I think this article was great and found it to be very much a good starting point. However, I also have accessibility concerns when using any of the vertical or horizontal menus that allow drop downs, or roll outs. What use are the sub links if I cannot get to them as a blind user or mobility impaired user?

    For example, try it yourself. Since I am blind (for example only, I am sighted) I only use a keyboard. A mouse would take forever to find a link I needed, so I must use TAB, and the Arrow keys. Using tab I can get to the main menu items, but I cannot get to any of the sub list items. I even tried the tabindex attribute, no such luck. So I was thinking about trying the accesskey, well that still doesn’t work.

    So, if you are going to use a menu like this and are providing information that a customer, vendor, or employee will need in order to use that information for their job, to place an order, or to find deeper information, you are eliminating a large chunk of web users. I am not specific to just blind users either. I am taking about those users that must use other forms of navigation other than “see, point, and click.”

  17. Hey Nick,love your menu but have am having a problem. I am also using ul on the page. The script seems to be overriding everything that i try. I tried using #nav infront of the link, and even putting an inline style, but the only thing that I can make work is using and ol and overriding the list type. Has anyone else run across this problem? I would appreciate any advise. Thanks.

  18. I had major problems until I removed all references to “padding” from my css classes and ids (other than those relating to the nav ul). Instead I am using html “cellpadding=xx” for table tags. Don’t like to do that but oh well.

    The only problem I still have with IE Mac is that after you follow a link from the menu, if you use the browser “back” button, the menu that popped up is still there and won’t go away.

    — margrit

  19. Congrats ! beautifull work here…

    id read carefully the article again and again, i´d saved the example page locally and… doesnt work i download the js, i had validated the path, but still doesnt work im a noob about css but im inproving it reading a lot but i like soo much that menu ! if some boy can explain why i appreciate it so much !

  20. I’m trying to use this menu but when I download the example and open it locally on my machine in Netscape, Opera, Firefox and it doesn’t work. It’s wierd because the example menu works on the web in those browsers. If anyone can give me a reason why this is I would really appreciate it.

  21. I really like this menu and I have been playing with it for some time now. One thing I don’t know how to do and I can’t seem to figure out is when you mouse out I don’t want the menu to disappear until you mouse over another link. Is that possible? If so how would one change the JS code to do this?

  22. Does anyone have any idea how to make the first set of buttons have different colour backgrounds (eg. First button is blue, next red etc.)?

    I have been trying for quite some time and I can’t get it to work.

  23. On your page,
    “Mystery IE6 Bug:

    During the development of this article, I uncovered a strange bug that I believe is only apparent in IE6. A background must be declared on the li a, else when a sub-menu stretches further (vertically) than the main menu itself, the links start to disappear before you have time to click them. Strange! Try it to see for yourself.”

    Putting in the background makes the menu elements disappear with Linux Galeon. Removing the background (background: #fff;) makes the problem disappear. I know that IE is more popular, but I’m still going to try to figure out how to make it work for both. Wish me luck.

    —ljl

  24. I discovered the solution to my own problem (the problem is: in IE5 for the Mac, if you follow a link and then use the browser back button to go back to the menu, the submenu that popped up before is still there and won’t go away): added the following to the JavaScript:

    node.onclick=function()
    {
    this.className=this.className.replace(” over”, “”);
    }

    so that the whole script is:

    startList = function()
    {
    if (document.all&&document.getElementById)
    {
    navRoot = document.getElementById(”nav”);
    for (i=0; i<navRoot.childNodes.length; i++)
    {
    node = navRoot.childNodes[i];
    if (node.nodeName==”LI”)
    {
    node.onmouseover=function()
    {
    this.className+=” over”;
    }
    node.onmouseout=function()
    { this.className=this.className.replace(” over”, “”);
    }
    node.onclick=function()
    {
    this.className=this.className.replace(” over”, “”);
    }
    }
    }
    }
    }
    window.onload=startList;

    — Margrit

  25. I have been looking for a solution for menu’s to display over an iframe.

    I have experienced problems with javascript menus, and this css version, displaying under the iframe content.

    Does anyone have any clues as to how the iframe content can be set to display below the drop down menu?

    I must use iframes to clip other web content and can’t avoid using them.

    Any help appreciated

    Justin

  26. Talking about menus, i’d like to show you one of mine ideas. It’s not really drop-down, but maybe this is a good place to do this.

    At http://www.itgmarinoni.it you can see the top navigation bar in the header (two anchors). Those two links are “inside” the header’s image). For explanations look at the css (www.itgmarinoni.it/src/css/cwm.css).

    Have anyone of you ever done a menu like this?

  27. I’m a newbie and want to get this to work. The sample link provided works fine for me in IE6. But the one I created for myself only works in Firefox, etc… In IE6, the menus pop out when I hover, but they don’t go away when I ‘dehover’

    Any help would be greatly appreciated.

  28. Does anyone have a workaround for the problem with

  29. I love this article. I recreated it and tried to add another level of sub menus, but I can’t make it work in IE. It works in Netscape without issue.

    I’ve tried variations of CSS where Behaviors are used, but Behaviors don’t work in IE/Mac.

    How can you make drop-down menus with multiple sublevels work?

  30. One less pleasant thing with CSS menus is that they disappear the moment you hover out of focus, and you’d have to start ‘menuing’ all over again.

    A way around this is to add some padding (top, right, bottom) to the ul’s, and compensate the top with a negative margin.

    Of course IE doesn’t play along here: it doesn’t grant the additional padding height. One way around this is to set a (1 pixel transparent) background image.

    I haven’t tested it thoroughly on all browsers, but it works on Op7, FF1, IE5/5.5/6, Konqueror.

    Cheers,
    Marcel.

  31. Test2
  32. Option2
  33. Contact Us
  34. i have used this from the article and i’m wondering if it’s possible to make it work like it should. Now, if you go over Test2, it shows Option1 and Option2 but also link1,2,3,4. What i want to know is: Is it possible to make the menu more complicated, like..more options to choose from.

    thanks in advance and i hope my explanation on this was clear.

  35. IIRC horizontal goes this way:
    <----------><----------><---------->

    Vertical, which is what this menu is, goes this way:
    <---------->
    <---------->
    <---------->

    the worst part is, in clicking thru the first few pages of the discusion section to see if this issue had been raised ( why can I not request to see ALL of the discussion in a single page so I can use firefox’s find feature more quickly? ) It seemed as though everyone else had accepted this reversal of the meaning of horizontal and vertical.

    aCk!!

  36. Hi

    Despite all the chat about repetitions, this tutorial has been invaluable to me despite having read other articles about nested lists. This was the cleanest solution I have found to date. However, although I have managed to create it on my page so it works fine in IE (bizarrely enough without using the Holly Hack), my sub links don’t work on any other browser and they display oddly. My test page is at: http://www.azuremarketing.com/cssAzure/index_test.htm and I have so far only added links from one section.

    I’m sorry if something has already been written about this in the discussion previously, but I’ve had a trawl through and can’t find any reference to it.

    I’ve been through my links and it may be that I’ve consused something through my use of an additional div.

    Any advise would be really appreciated.

    Many thanks

    Vicky

  37. I’ve been trying to get this code to show multiple menus as the menu I need is in a php loop and is shown multiple times with some changes done to it, the entries differ.

    Now the problem is that in IE and Opera only the first instance of the menu works and others only show the main ul and don’t “dropdown” but in firefox everything works perfectly.

    Any ideas on how this would be fixed?

  38. I’ve been trying to get this code to show multiple menus as the menu I need is in a php loop and is shown multiple times with some changes done to it, the entries differ.

    Now the problem is that in IE and Opera only the first instance of the menu works and others only show the main ul and don’t “dropdown” but in firefox everything works perfectly.

    Any ideas on how this would be fixed?

  39. Is there a way to develop this in a similar manner, except this time horizontal rather than vertical…

    Im really new to CSS so i wont be able to do it myself 🙁

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career