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:
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)
very nice tutorial :)
thanks a lot!!
hi Sir,
I tried your codes and it worked fine… except that when i dropped down your sub menu from your main menu, it overlapped with the background picture and website’s wordings right above the picture(below your menu), how do I make the submenu overwrite the website’s background picture and wordings when i click on select the items on the menu…
kindly assist…
Thanks in advance,
Andrew
hi Sir,
Thanks for the scripts, it worked. But i got one problem.
How do the submenu that’s extended from the main menu overrides the website’s background pictures and background wordings as the submenu is shown when the mouse is clicked to the submenu? as they are overlapping with the submenu’s item.
Thanks,
Andrew
I have been looking everywhere for something like this!
One problem: I cannot make the nav bar center (using margin:0 auto; or width:100%, or anything else I can think of).
Any suggestions would be greatly appreciated – I can’t use it otherwise! :-(
One other small question: I’ve been fiddling a bit, and now the dropdown menu starts about 5px below the main menu (iow, there is a space of that width between the two). What in the CSS controls that?
Thanks!!
wow love the menu tutorial going use it for sure
I want this effect on click menu.Please Suggest me
It is working fine on hover can it be change when i click on perticular menu item.
Awesome tute – thanks Kriesi, you saved my life.
Cheeky question – I know this is probably a huge mission, but is there any possibility of setting rounded corners or such like to these drop downs?
*****
To WLHH, I think I may have some answers for you based on what I’ve been playing around with on my site just now. I’m a complete noob at all of this so I’m sorry if these are not the best solutions, but they should get you up and running for the time being.
I set the width of the bar to fit a table on my page
#nav{width:42em
– but this only affected the menu bar when I also set the width of the first set of links:
#nav a{width:7.6em;
You can center your links in the same bracket with
text-align:center
and then just play around with those two width figures until everything spreads out as intended.
Re: your second issue
I have the same problem in IE with the drop downs appearing beneath a gap – which effectively means you can’t click on any of them. But I found that if you set the TOP value under nav ul (it’s originally 1.5em) to slightly lower than the #nav line-height value (they’re originally equal at 1.5em) then it alines itself… I had to set mine to line-height:1.5em vs top:1.2em. This puts things a bit off when you hover over the topmost dropdown link (especially in FF), but it’s a small price to pay for functionality.
Loved this tutorial!!
Question:
Is there a quick way to make the html validate?
I found the answer to my question:
1 HTML
3.1 jQuery
3.2 Mootools
3.3 Prototype
The tag must close after all dropdown content and not before in order to have valid XHTML.
EXAMPLE:
li — 1 html
ul
li /li
li /li
li /li
/ul
/li
this is EXACTLY what i’ve been looking for, and very tight optimized code! but i have one problem: for my application it’s a necessity for the parent element to remain highlighted (or selected) while the child menu is open. Currently, when mousing over the child links the parent is no longer highlighted. so it only has a hover state, and not necessarily a “selected” state. I’ve played around with this for a while and I can’t seem to get it to work. Is there a way to implement this? Much appreciated!
Awesome tutorial!!!
But, I was trying to add more nested lists but it just won’t work T_T
ooops! never mind my first post.. :P
Thank you so much!
By the way, I really love your site!! ^__^
Very nice, thank you!
Very nice. Thank you.
Has anyone managed to convert this to produce a dropline menu – e.g. http://www.cssplay.co.uk/menus/pro_dropline7.html – but without the mass of conditional comments that is used on that example to make it work in IE6?
Thanks! I have been trying tutorials out for the past hour and yours has been the only one that worked.
HI there and thanks for a great menu – i am very new to scripting and currently building my site. after trying several menus (namely from dynamivdrive) i came across yours which seems more lightweight to me. In any case i have tried to modify it to fit my design but with only partial success – maybe you can help with couple of questions…
A test page is here: http://michelmoalem.awardspace.com/index5.html
1. when playing video in an embeded player from vimeo (see menu item ‘showreel’) the dropdown menu doesn’t show over it… can it be done?
2. after hacking the css file a bit i seem to have lost the sliding effect that yours seems to have – how do i restore it and slow it down a bit if possible?
3. ideally i would like to have the menu below the screen
(as in http://michelmoalem.awardspace.com/index3.html) and slide up – can it be done with your script?
thank you again
michel
The tutorial is great. It helped a lot. I was trying to do something similar and just didn’t realize that ul li.mouseover() will be active even for children of the LI. Thanks again!
Anyone know of a tutorial or similar that describes how to take this particular jQuery menu and have the links dynamically loaded from an xml file? or rather I’m trying to implement this menu and the asp menu control in asp.net 2.0 together. if anyone has any advice and/or has done this, please let me know. to be able to integrate this jQuery menu with asp.net’s site map security based asp menu would be so great.
Thanks.
also i noticed with this menu you have to add some extra css styles to get the borders just right — as with the current implementation it doubles up the borders in certain areas. it doesn’t show up in the demo because of the chosen border color is the same as the background color.
@Thomas
Try adding the following two lines to the script itself:
(on mouseover – first function)
$(this).addClass(“hovered”);
(on mouseout – second function)
$(this).removeClass(“hovered”);
And just style the hovered class the way you want it to show that the current menu item is selected. This works okay for me.
Though the main problem I’m facing at this point is… if a user moves away from the menu, it vanishes a bit too fast… and with my site having four-level menus, that can be quite the nuisance. What I want to achieve is… have it delay hiding the menu if the mouse moves away from the menu itself, but have it vanish immediately if the mouse moves over a different drop-down. Suggestions anyone?
thanks for this tutorial. I am trying to use this with the latest jquery (jquery-1.3.2.min.js) and it doesn’t seem to work but works with previous versions.
thanks
éžå¸¸æ¼‚亮的èœå•ï¼Œæ„Ÿè°¢ä½œè€…ï¼
Thank you, so much.
éžå¸¸å–œæ¬¢ä½ çš„Blog,很有收获(good job)。
Hi im having the problem of the sub menus falling behind other parts of the web it has been told that a Z-index in the CSS solves this but i dont know how it should be can anyone please help me…?
Thanks in advice
Has anyone tried to implement easing plugin onto this simple drop down menu ?