Create a multilevel Dropdown menu with CSS and improve it via jQuery

Some of you might have noticed, I have a partiality for sleek menus. As I recently had to create a multi level dropdown menu for one of my customers, I wanted to improve it with a little bit of jQuery, but couldn’t find a script that accomplished what I needed.

So I decided to build this menu from scratch and share my thoughts as well as the code with you.

So before we start: this is what we are going to build


The first part of this tutorial is dedicated to the task of building a working CSS-only dropdown menu (also known as suckerfish menu), the second part will show you how you can pimp the whole thing with a few lines of jQuery.

The CSS-only menu is cross browser tested and from what I can tell works with all browsers except for IE6.
The Internet Explorer needs the addition of our jQuery function to work properly.

To create a CSS-only dropdown menu that works without Javascript (even in IE6), you need tons of extra markup and CSS, if you really need this for any reason check out Stu Nicholls CSSplay, he addresses this problem with heavy (ab)use of conditional comments =)

Now that you have a little bit of background information, lets create our own menu:

First of all we need the XHTML Structure of our soon-to-be terrific menu. We will use a nested list for this purpose, top level list id is “nav”:

<ul id="nav">
    <li><a href="#">1 HTML</a></li>
    <li><a href="#">2 CSS</a></li>
    <li><a href="#">3 Javascript</a>
        <ul>
            <li><a href="#">3.1 jQuery</a>
                <ul>
                    <li><a href="#">3.1.1 Download</a></li>
                    <li><a href="#">3.1.2 Tutorial</a></li>
                </ul>
            </li>
            <li><a href="#">3.2 Mootools</a></li>
            <li><a href="#">3.3 Prototype</a></li>
        </ul>
    </li>
</ul>

Thats it for the HTML part; without CSS styling our menu looks like this: Step 1

Now for the stylesheet part:

#nav, #nav ul{
     margin:0;
     padding:0;
     list-style-type:none;
     list-style-position:outside;
     position:relative;
     line-height:1.5em;
 }

This removes the indents browsers tend to make, as well as the bullets from #nav and all its child-ul elements. The “position:relative” is needed since we will arrange some of the contained elements with position:relative and absolute. This is necessary since relative and absolute positioned elements are positioned according to their containing blocks with a position attribute, other then static.

Line-height defines the height of each list item. You could set the height attribute for your list-items to define their height, but line-height will center the link text vertically without the need to play with margins and paddings.

 #nav a:link, #nav a:active, #nav a:visited{
    display:block;
    padding:0px 5px;
    border:1px solid #333;
    color:#fff;
    text-decoration:none;
    background-color:#333;
 }

#nav a:hover{
    background-color:#fff;
    color:#333;
}

This one is pretty straight forward:
it will style each hyper link in our menu a little bit. At this time the menu looks like this: Step 2

Now lets add some more styles:

#nav li{
    float:left;
    position:relative;
}

This will align our list elements horizontally.

#nav ul {
    position:absolute;
    width:12em;
    top:1.5em;
    display:none;
}

This will position the nested Lists right beyond the main menu and give them a width of 12em. The width attribute is needed so that the list items within display vertically again. The Top attribute should have the same value as the line-height attribute we defined for #nav.

#nav li ul a{
    width:12em;
    float:left;
}

This will set the width of the hyper links to 12 em (which in combination with the width of the UL set above results in a horizontally displayed sub menu, despite of the ongoing float:left)

#nav ul ul{
	top:auto;
	}

#nav li ul ul {
    left:12em;
    margin:0px 0 0 10px;
    }

#nav li:hover ul ul, #nav li:hover ul ul ul, #nav li:hover ul ul ul ul{
    display:none;
    }
#nav li:hover ul, #nav li li:hover ul, #nav li li li:hover ul, #nav li li li li:hover ul{
    display:block;
    }

#nav ul ul and #nav li ul ul define where we display the sub menus.

The hover states define which items we want to show when hovering over an item (only the next sub level, not all of them)

After applying these styles we got this menu: Step3

If you are working with a browser other than IE6 you should have a basic dropdown menu now.

Gogo jQuery!

So lets spice up the menu a little bit. First of all here is the whole jQuery Code I used to create the effect:

function mainmenu(){
$(" #nav ul ").css({display: "none"}); // Opera Fix
$(" #nav li").hover(function(){
		$(this).find('ul:first').css({visibility: "visible",display: "none"}).show(400);
		},function(){
		$(this).find('ul:first').css({visibility: "hidden"});
		});
}

 $(document).ready(function(){
	mainmenu();
});

Step by step description:

$(" #nav ul ").css({display: "none"}); // Opera Fix

This is a small fix for Opera, which doesn’t hide the menus fast enough, if you hover above them and so creates a flickering effect. $(” #nav ul “) is the jQuery way to select all unordered lists in #nav. Usage of this is similar to selecting CSS elements. The .css({display:”none”}) sets the display attribute for all Unordered lists to none.

$(" #nav li").hover(function(){ // here goes mouse over effect
                  },function(){ // here goes mouse out effect
                               });

This is the jQuery function for hovering. Really simple to use: first function lets you define what happens when you hover over a specific item( in our case a list item), second function is used for the mouse out event.

$(this).find('ul:first:hidden').css({visibility: "visible",display: "none"}).show(400);

This function finds the first hidden unordered list within the currently hovered list item and shows it. The function “.show” works only under specific circumstances, this is why we set the display to none. The number between the braces defines the animation speed in milliseconds.

$(this).find('ul:first').css({visibility: "hidden"});

This is the mouse out event: we use visibility instead of display since the show function mentioned above, sets display to “block” at the end of the animation. This way if you would hover just a short moment over the item the item would not display for the ongoing animation and then pop out all of a sudden. Using visibility prevents this flickering.

 $(document).ready(function(){
	mainmenu();
});

This function will call our mainmenu() function as soon as the html document is ready.

We are done now, if you can’t get this to work for any reason, here is a working example for download:

Download
Includes: HTML File, CSS File, Javscript Files

Have fun creating your own menu ;)

Update :

I have added some small fixes to the script which were suggested by some of my readers, so thanks for adding improvements. ;)

Another thing I wanted to note: I have seen this script in many templates and wordpress themes now, often used in conjunction with one of wordpress automatic list generating features (wp_list_categories, wp_list_pages)
If you use it that way wordpress adds a title attribute to each link, which can create a flickering effect when the browser tooltip for the title appears. If you are using the script this way you should add the following line of jquery at the beggining of the script to remove the titles:

$(" #nav a").removeAttr("title");

(Last updated 18.09.2008)

Tags: , ,
398 replies
« Older CommentsNewer Comments »
  1. ST Verschoof
    ST Verschoof says:

    #nav a:link, #nav a:active, #nav a:visited{
    display:block;
    padding:0px 5px;
    border:1px solid #333;
    color:#fff;
    text-decoration:none;
    background-color:#333;
    }

    #nav a:hover{
    background-color:#fff;
    color:#333;
    }

    Just a TIP!
    Change it into:

    #nav a:link, #nav a:active, #nav a:visited{
    outline: none
    display:block;
    padding:0px 5px;
    border:1px solid #333;
    color:#fff;
    text-decoration:none;
    background-color:#333;
    }

    #nav a:hover{
    outline:none;
    background-color:#fff;
    color:#333;
    }

    You’ll see how well that works and notice that it looks a little bit better!

  2. Linda
    Linda says:

    This is just a trial page I am working on, so I implemented your script as I intend to add sub menus later as needed. It looks great and is working on IE but when I open this page in FIREFOX, everything went out the door. The menu has broken through the cell and has displaced the layout…what did I do wrong? Or ?

    HELP! total novice at this stuff, but love learning new tricks.

  3. Dhiva
    Dhiva says:

    Hi

    In the Jquery code $(document).ready (function() {mainmenu();}));

    I am getting an error message, “object missing”, why is that?

  4. Srikanth Reddy.S
    Srikanth Reddy.S says:

    Hi i want to create multi level menu bars.
    Can any one help me out.please…

    Thanks in advance.

    Srikanth Reddy.S

  5. gabe
    gabe says:

    I got this working great am I using it for a list of links from A-Z in a box. This works great in FF but in IE the pop out menu hides behind everything I tried to Z-index but noting can someone PLEASE help?

  6. Nadun
    Nadun says:

    Hi,

    I can’t tell you how happy I am after finding your tutorial cause I couldn’t find a good tutorial about css menus. With your help I will start creating my own menus and use them. Thanks for this great help.

  7. ronsa
    ronsa says:

    I’ve noticed that the dropdown menu doesn’t work properly on IE7 without those jQuery-things.

    Just test Step 3 menu by hovering the submenu “JavaScript->jQuery->Download” and then move your mouse out of the menu, then open the menu again. That “JavaScript->jQuery->Download” hierarchy should be open but it’s empty.

    http://i38.tinypic.com/2ewz3vr.jpg <- picture about this.

  8. KT
    KT says:

    thanks for the great tutorial!

    Does anyone know what the fix is for having multiple menus work in IE 6? i.e., try this:

    1 HTML
    ….

    1 HTML
    ….

    in IE6 only the first menu dropdown works (ok in FF)

    Thanks!

  9. Glen
    Glen says:

    Hi

    I have modified the code in this example to suit my needs. Its all working fine in FF, the dropdown menu shows good. But its not working in IE 7

    Here s my css:

    body, ul, li {

    margin: 0px;
    padding: 0px;

    }

    #nav, #nav ul { position: relative; list-style: none; height: 32px; line-height: 32px; }
    #nav li { float:left; line-height: 32px; }
    #nav li a { display: block; text-indent: -3000px; overflow: hidden; }
    #nav li ul { position: absolute; list-style: none; display: none; width: 300px; }
    #nav li ul li { float: left; line-height: 32px; }
    #nav li ul li a { display: block; position: relative; height: auto; width: 300px; }
    #nav li:hover ul { display: block; }
    #nav li:hover ul li a { padding-left: 5px; text-indent: 0px; }

    #nav0 a {width:71px;background:#3b3d27 url(/i/nav0.gif) no-repeat;}
    #nav0 a:hover {background:#9883a7 url(/i/nav0.gif) 0 -32px no-repeat;}
    #nav1 a {width:102px;background:#3b3d27 url(/i/nav1.gif) no-repeat;}
    #nav1 a:hover {background:#9883a7 url(/i/nav1.gif) 0 -32px no-repeat;}
    #nav2 a {width:128px;background:#3b3d27 url(/i/nav2.gif) no-repeat;}
    #nav2 a:hover {background:#9883a7 url(/i/nav2.gif) 0 -32px no-repeat;}
    #nav3 a {width:119px;background:#3b3d27 url(/i/nav3.gif) no-repeat;}
    #nav3 a:hover {background:#9883a7 url(/i/nav3.gif) 0 -32px no-repeat;}
    #nav4 a {width:99px;background:#3b3d27 url(/i/nav4.gif) no-repeat;}
    #nav4 a:hover {background:#9883a7 url(/i/nav4.gif) 0 -32px no-repeat;}
    #nav5 a {width:141px;background:#3b3d27 url(/i/nav5.gif) no-repeat;}
    #nav5 a:hover {background:#9883a7 url(/i/nav5.gif) 0 -32px no-repeat;}

    #nav1 ul li a { background: #afafd9; color: #05036e; }
    #nav1 ul li a:hover { background: #b97df2; color: #05036e; }

    #nav3 ul li a { background: #afafd9; color: #05036e; }
    #nav3 ul li a:hover { background: #b97df2; color: #05036e; }
    /*
    #nav20 a { background:#9fddfd; color: black;}
    #nav20 a:hover { background:#FFFFFF; color: black;}
    #nav21 a { background: #9fddfd; color: black; }
    #nav21 a:hover { background: #FFFFFF; color: black; }
    #nav22 a { background:#9fddfd; color: black;}
    #nav22 a:hover { background:#FFFFFF; color: black;}*/

  10. Bosco
    Bosco says:

    Hi Kriesi,
    I’ve bought your cool Communizine. How can i setup the commnets to receive the real gravatar of my commentors?
    I appreciate your answer, by email, if you can.
    Thanks a lot,
    Bosco

  11. Mikunda
    Mikunda says:

    Hello,

    The menu is great. After testing so many others, this one is like a breath of fresh air. Great work. Just a small quirk…

    When in Firefox, and when not on the main index page, let’s say if I go to a subpage:
    http://laurelhillschool.org/new/nursery.html
    if I re-load the page, there pops up a large gap between the main and sub-menus. What is the problem? I couldn’t figure it out. Could it be because my subpages are in a sub-folder separate from the index.html?

    Thank you so much for your thoughts. I know you probably are way to busy to respond. Where can I give a donation to the project? Thanks a lot.

  12. craig
    craig says:

    Can you make another one but instead of using id #nav, use class .nav so that people can have multiple menus like that in one page.

    Meanwhile, doing this script by css class , it would be more usable in more case

  13. craig
    craig says:

    Oh, I’ve just check out your portfolio. Nothing but one word, amazing!

    I like the blog with beach theme and i like this site with the wonderful javascript menu.

    You have mad skill at photoshop, am I right ?

Trackbacks & Pingbacks

  1. […] Not exactly. The menu I have currently is a based on, Create a multilevel Dropdown menu with CSS and improve it via jQuery | Kriesi.at – new media design My goal is to have the drop menu within to display another sub menu inline. Is this […]

  2. […] 4- Create a multilevel Dropdown menu with CSS and improve it via jQuery […]

  3. […] 4- Create a multilevel Dropdown menu with CSS and improve it via jQuery […]

  4. […] Tutorial para criar um belo menu com sub-itens (demonstração online) Plugin para cortar fotos com jQuery. […]

  5. […] 20. Create a multilevel Dropdown menu with CSS and improve it via jQuery […]

« Older CommentsNewer Comments »

Comments are closed.