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
Newer Comments »
  1. Roshan Burnham
    Roshan Burnham says:

    Hello,

    I wanted to drop this line to let you know that I really appreciate this tutorial and couldn’t be more thrilled with the timing of your post.

    I recently implemented a suckerfish drop-down menu on a site that I am currently building, but was concerned 1) with how to create multiple-drop-down’s and 2) “suping up” the otherwise bland style of the menu. Although had I really sat down and thought about the prospect for multiple-drop downs, seeing a more seasoned professional such as yourself post this helpful tutorial has emboldened me with the confidence to pull it all off.

    Thank you!

    Roshan Burnham

  2. Steven
    Steven says:

    I was in the exact same predicament as the first poster! I implemented the suckerfish menu but I kept screwing it up every time I tried to style it my own way. Nothing seemed to work in IE6!! Wish I found your tutorial earlier – before I bought the CSSwriter for $50 yesterda – because it looks like good one. Thanks

  3. Aaron
    Aaron says:

    This is great!

    Can you use other effects like a fade or slide down?

    Can you make the dropdowns transparent?

    Also do you think this could implemented for a vertical nav that has menus the open to the left?

    Thanks and great tutorial!

  4. curtismchale
    curtismchale says:

    Very slick. Thanks for taking the time to make this available. I have bookmarked if for later reference through evernote. I have been beefing up my CSS abilities and this is a good jump for me.

  5. Kriesi
    Kriesi says:

    Aaron: Yes to every one of your questions: a vertical fly-out menu would need a reworked css file whereas effects like fade or slide-down only need some configuration of the jQuery script. Basically you only have to change the .show(400) function to .fadeIn(400) or .slideDown(400)

    To display the menu transparent you have to change a little more:

    you must delete the opera fix line and change
    $(this).find(‘ul:first’).css({visibility: “visible”,display: “none”}).show(400);

    to

    $(this).find(‘ul:first’).css({opacity:0, visibility: “visible”}).animate({opacity:0.8},400);

  6. Gavin Doolan
    Gavin Doolan says:

    Fantastic, I was looking for an updated suckerfish menu. I will be implementing this on a new site I’m developing in Drupal. I will let you know how I get on, but if all goes well this will be an awesome addition.

    Thanks for the extremely well detailed post. Must have been time consuming to put together.

  7. Majesticskull
    Majesticskull says:

    Very nice solution! Thanks!
    But it’s make submenus staying side by side instead one on top of another? My English is very bad, but I hope that I understand.

  8. Kriesi
    Kriesi says:

    Not easily done with my code since we use two different techniques:
    I hide the submenu with “display: none” whereas the other script hides the submenu by positioning the UL outside of the view port (top:-999em)

    You would need to rewrite every file (CSS, HTML and Javascript File) to make this work.

  9. mrbill
    mrbill says:

    When creating CSS menus that are based on a list, is there any way to get around having to modifying every html file if you need to modify the menu?

  10. Jonathan
    Jonathan says:

    I tried to implement your menu on a site im working on and the drop down is going behind a div in IE 6/7. If you email me I will send you a link to the site though it is a site I’m working on for someone so I can’t make it public yet…

    Appreciate any assistance you can provide.

  11. Kriesi
    Kriesi says:

    @mrbill: phps include function would solve this problem

    @JakeZ: of course you can use prototype, but since I didn’t use it for months now I cant help you here. All you need is a basic dropdown or slide up script, shouldn’t be to hard to find a tutorial on this topic. From what I remember, the prototype+scriptacolous code would look something like this:
    Effect.BlindDown(‘element_to_display’, {duration:2});

    @Jonathan: sounds like a z-index problem. just send me the link via contact form, I will take a look.

  12. Gabrielle
    Gabrielle says:

    Thanks – It’s always wonderful to see something boiled down to its very essence!
    I am new to jQuery and only started to explore it a couple of days ago: so please forgive this probably stupid question.
    I understand that adding the jQuery code to your dropdown menu, makes animation effects possible, but why does one still need all of the CSS doing the display: none/block? Why doesn’t jQuery take care of this in its hover function?
    Thanks for clearing up this fog and greetings from Montreal
    Gabrielle

Trackbacks & Pingbacks

  1. […] When it comes to drop-down menus, there are two techniques: CSS and Javascript. I personally tend to take the javascript route, just because there is more you can do functionally that can’t be done with CSS alone. Stuff like delays and animations… However, to stay true to the web designers mantra of keeping design separate from content separate from functionality, we should ideally make the menu work with javascript turned off. The best way to handle this is to create your drop-down menu with CSS-only, then just javascript to enhance the functionality. […]

  2. 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 accomplishe…

  3. […] Create a multilevel Dropdown menu with CSS and improve it via jQuery | Kriesi.at – new media design As usability and accessibility people get bored with current ‘issues’ they’ll move on to better drop down menus (if they admit they’re useful at all). (tags: ajax animated code components design development jquery css menu javascript dropdown tutorial multilevel navigation) […]

  4. […] en JQuery: Link 47 Formularios Ajax+CSS: Link TableCloth: Link Menú Dropdown Multinivel CSS+JQuery Link Tooltip & Image Preview via JQuery Link Full CSS Layout Link  Css Float […]

  5. […] Create a multilevel Dropdown menu with CSS and improve it via jQuery | Kriesi.at – new media design […]

  6. […] Multilevel Dropdown CSS menu – Learn how to build a multilevel dropdown menu with CSS and then improve it with jQuery.  It’s totally unobtrusive – even if javascript is disabled you’ll still be able to use this menu. Welcome, Visitor. Subscribe to our RSS Feed and consider adding this article/site to your favorite social bookmark site if you find it useful. Thank you! | Subscribe to RSS […]

  7. […] Tutorial para crear un menú desplegable en CSS y agregarle un poco de efectos con jQuery. 0 # […]

  8. […] Enlace y Demo. Creando un menú de navegación con el evento KeyPress y JQueryAñade profundidad con sombrasCrea tu propio lightbox con JqueryFormulario css usando listas (ul y dl)10 scripts para crear gráficas gratuitos Tags: JQuery, tutoriales jquery Puedes seguir los comentarios en el feed RSS 2.0 . Puedes dejar un comentario, o trackback desde tu propia web. […]

Newer Comments »

Comments are closed.