Share!

How to Create a Horizontal Dropdown Menu with HTML, CSS and jQuery

Menus play an essential part on the web. They allow users to find their bearings and help them navigate your website. When designing menus, usability is the key.

Beginners often struggle with the basics. In this tutorial I'm going to show you how to create a simple, usable and functional horizontal menu with HTML and CSS. I will also dive a little bit into jQuery to add animations to your menu.

How to Create a Horizontal Dropdown Menu with HTML, CSS and jQuery

This tutorial assumes you have a basic knowledge of HTML and CSS. It’s recommended to use a CSS reset for consistency. I use the one by HTML5Doctor.

The Basics

Let's start with the basic HTML structure of the menu:

<ul id="coolMenu">
<li><a href="#">Lorem</a></li>
<li><a href="#">Mauricii</a></li>
<li><a href="#">Periher</a></li>
<li><a href="#">Tyrio</a></li>
<li><a href="#">Quicumque</a></li>
</ul>

A menu consists of an unordered list, and each list item contains a link with the text. Don’t create unnecessary divs. You don’t need any.

To add a sub menu simply nest another unordered list inside the item that's going to have the sub menu, like this:

<ul id="coolMenu">
    <li><a href="#">Lorem</a></li>
    <li><a href="#">Mauricii</a></li>
    <li>
        <a href="#">Periher</a>
        <ul>
            <li><a href="#">Hellenico</a></li>
            <li><a href="#">Genere</a></li>
            <li><a href="#">Indulgentia</a></li>
        </ul>
    </li>
    <li><a href="#">Tyrio</a></li>
    <li><a href="#">Quicumque</a></li>
</ul>

As you can see, creating the structure is very simple. This is how it should look in your browser at this stage:

Stage 1

There are multiple ways to set up the CSS for a horizontal menu. After many years I found that this is the quickest and cleanest way to do it:

#coolMenu,
#coolMenu ul {
	list-style: none;
}
#coolMenu {
	float: left;
}
#coolMenu > li {
	float: left;
}
#coolMenu li a {
display: block;
	height: 2em;
	line-height: 2em;
	padding: 0 1.5em;
	text-decoration: none;
}
#coolMenu ul {
	position: absolute;
	display: none;
z-index: 999;
}
#coolMenu ul li a {
	width: 80px;
}
#coolMenu li:hover ul {
	display: block;
}
  • I decided to float the whole menu to contain it but you can use overflow hidden or even set a fixed width for the same purpose.
  • It is important to float the list elements rather than the links.
  • The links should be displayed as blocks, otherwise, they won’t behave as expected.
  • Absolute position the submenu and hide it to remove it from the regular flow and make it invisible. Also, set a high z-index to prevent the submenu from showing behind other elements.
  • Set a height for the link elements and the line-height equal to the height to center the text vertically. By specifying a fixed height instead of just using padding you avoid flickering problems with jQuery animations later on.
  • Even though it’s not necessary to set a fixed width for the submenu items, it’s always a good practice. It allows you to style them more consistently later on.
  • Notice that the hover state is set on the list element and not the link.

With all this set, the menu should be already working. Try opening it in your browser and hovering over the third option to show the sub menu.

Stage 2

Improving Usability

This step will cover how to style the menu with some basic CSS to make it more accessible.

/* Main menu
------------------------------------------*/
#coolMenu {
	font-family: Arial;
	font-size: 12px;
	background: #2f8be8;
}
#coolMenu > li > a {
	color: #fff;
	font-weight: bold;
}
#coolMenu > li:hover > a {
	background: #f09d28;
	color: #000;
}

/* Submenu
------------------------------------------*/
#coolMenu ul {
	background: #f09d28;
}
#coolMenu ul li a {
	color: #000;
}
#coolMenu ul li:hover a {
	background: #ffc97c;
}

Keep in mind this is very basic, and is meant to be just an example. You can style this however you want. The important thing to remember here is, as I mentioned before that the hover states, are styled in the list items and not the links.

This is how the menu looks so far:

Stage 3

Adding Animations

This final step is not necessary but it’ll help you add animations to your menu with simple jQuery. The first thing you need to do, of course, is to call the latest jQuery plugin on your website:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>

Now, let’s add a "noJS" class to the submenu to be able to unhook the hover css state in jQuery. This will also ensure that the menu will still work when javascript is disabled.

<li>
    <a href="#">Periher</a>
    <ul class="noJS">
        <li><a href="#">Hellenico</a></li>
        <li><a href="#">Genere</a></li>
        <li><a href="#">Indulgentia</a></li>
    </ul>
</li>

You also need to add the class to the sub menu CSS hover state:

#coolMenu li:hover ul.noJS {
	display: block;
}

Now that everything is set let’s add some magic:

$(function(){
	$('#coolMenu').find('> li').hover(function(){
		$(this).find('ul')
		.removeClass('noJS')
		.stop(true, true).slideToggle('fast');
	});
});

The code is pretty explanatory. The script finds the immediate children list items and adds a hover function. Inside the function it removes the "noJS" class since we’re using JavaScript, and then it tells the menu to slide down on hover and to slide up on un-hover. This is achieved with the slideToggle function. The stop function prevents the animation from repeating itself if we hover multiple times.

Further Notes

The menu should work in IE7+ and all other modern browsers. I didn’t bother to support IE6. I’m sure it could work with some fixes here and there but that’s not the purpose of this tutorial.

I encourage you to try some CSS3 properties to style your menu, the possibilities are almost endless. I suggest you use the Colorzilla gradient generator to create your gradients.

I look forward to see what you can do.

Advertise with us

Author

Cedric Ruiz is a freelance graphic and web designer/developer with a passion for computers and technology. He actually studied 3D animation but took a totally different path. He needs to learn something new everyday and he loves challenges and teaching people new skills.

45 Comments

Say Something
  1. Paginas
    June 3, 2011 at 11:14 pm

    Navigation menus are the most important element one should pay attention when designing a website. Web-developers can create user-friendly horizontal or vertical navigation menus using CSS. Javascript makes it possible to create more interactive, more responsive and more flexible navigation to any website.

  2. Joe
    June 4, 2011 at 12:05 am

    By using css transitions you could achieve that scrolling effect as well. No 31,31 KB jquery-include needed

    • Cedric Ruiz
      June 4, 2011 at 3:14 am

      Of course you can, but with jQuery it'll also work on browsers that don't support css transitions.

  3. jlafay
    June 4, 2011 at 1:10 am

    When I tried the example, the submenu is showing to the right underneath the main menu item. I'm new to css so I'm not sure where and how to fix it. Is there something I'm missing that maybe didn't make to the blog post?

    • Cedric Ruiz
      June 4, 2011 at 3:22 am

      What browser are you using?
      I'm not sure what could be the problem but make sure the submenu "#coolMenu ul" has "position: absolute".

      • June 6, 2011 at 4:01 am

        I have the same issue, in ALL browsers (except IE; I don't have IE installed). I even tried copying and pasting the code, linking and un-linking the stylesheet, but the result is still the same. The sub menu is not positioned directly underneath it's parent, but to the right of it, indented slightly.

        Here's a screenshot of what it looks like in chrome: http://ow.ly/i/cxv4

        • Cedric Ruiz
          June 6, 2011 at 4:28 am

          Ok, I found the problem. This is happening because you're not using the css reset.
          I recommend always using a reset for consistency across browsers.
          But, if you don't want to use it or you're using your own css reset and it's still happening just add "padding: 0;" to "#coolMenu ul" and it should work fine.

          • June 6, 2011 at 5:09 am

            Thanks! Yeah I missed the line about the reset!

          • john
            October 24, 2011 at 7:24 pm

            two basic questions
            my animation part doesn't work
            so where does the code beginning with $(function(){ go?
            in a separate js folder? is so what do you name it?
            and where exactly does the padding: 0 referred to above go?
            there are a couple of sections which say #coolmenu ul

  4. Mickey
    June 5, 2011 at 5:16 pm

    Hello.

    Very nice tutorial! Thank You!

    I have to say some words, though :)

    I see more and more posts on usability of UI and one of the critics about menu is that it should not be "nervous", meaning - it should not open sub-menu on immediate "hover", but wait some time, because user may unintentionally hover the menu with mouse many times. The same is for "blur".

    So, as an usability point - it would be "correct" to add some delay before opening the menu and closing it.

    Just some thought.

    • Cedric Ruiz
      June 5, 2011 at 5:27 pm

      You can use the hoverIntent plugin.

      • Mickey
        June 5, 2011 at 5:29 pm

        Yes, I was referring to something like that :)

        Thank You.

  5. June 6, 2011 at 12:57 pm

    Yes, I was learning to something likeit

  6. June 6, 2011 at 5:13 pm

    Good tutorial, but its not working in IE6.
    I think IE6 doesn't support child selectors.

    • June 6, 2011 at 5:52 pm

      The child selectors are easily swappable for ul li ul li styles etc so shouldn't be a barrier to getting it working on IE6. However, the li:hover will not function in IE6 and this requires a bit more of a workaround. You can use JavaScript to add a hover class (such as li.hover) to the li's on the mouseover event and remove it on the mouseout even. This way the styling will remain concise and the functionality consistent across all browsers.

      Finally, if you want more nice usability tweaks such as delaying hiding/showing and also widening the sensitive areas of the menu so they don't disappear as soon as you roll slightly off them I have always found the Uvumi dropdown menu easy to implement using mootools. The advantage of this particular option is the ease of styling and the fact that the html remains clean and valid.

  7. June 6, 2011 at 5:41 pm

    Thanks for sharing the fundamentals. It's easy to find hundreds of downloadable templates for cool looking dropdown menus, but to actually know how it operates and what's involved in its development is a much better resource.

  8. Rana Mukherjee
    June 6, 2011 at 9:57 pm

    Nice

  9. June 28, 2011 at 11:08 pm

    I always find drop downs a little tricky especially when trying to get them to look and work the same in IE6. I have a HTML/CSS driven drop down I use normally with an alternative stylesheet for IE6. However the other day it was conflicting with my J Query, I might give this a try hopefully it works perfectly! I think adding J Query to your navigation always makes it look nicer and adds a little bit more animation to the rollover states.

  10. July 1, 2011 at 5:25 am

    I am trying to add a submenu to my menu. I have tried adding the ul inside of the ul but the only thing that
    does is display the two submenu items visible below the main menu item. I tries using hide in the unordered
    list but that hid the whole horizontal menu bar, not the two submenu items. I am sure it is a css styling problem I just don't know what it is. The problem I am running accross with instruction on this is that I already have a menu bar. I just want to add a drop donw to one of the blocks because I have 2 different pages I need to go to. All the instruction I am running across is building a whole menu bar which I already have. Any ideas?

  11. August 4, 2011 at 12:21 pm

    Hi,

    I am trying to add vertical menu for my website. I have used your horizonal menu bar and it has worked well. I need a vertical bar which does not use javascript. Can you direct me to right place?

    -jody

  12. August 21, 2011 at 3:26 am

    Hi,
    Very nice. I like the smooth effects of the jquery. Has anyone gotten this to work in ie6? Also, anyone successful in adding a submenu to the first submenu? Like to keep building on this terrific base. Thanks for contributing.

    Lynne

  13. praveen
    September 21, 2011 at 11:43 pm

    thank you!

  14. September 22, 2011 at 5:04 pm

    I can fix the IE6 finally...
    change the css as below
    #coolMenu {
    float: left;
    width: auto;
    }
    #coolMenu li {
    width: 89px;
    float: left;
    }
    #coolMenu > li {
    float: left;
    width: 89px;
    }

  15. Samson
    October 13, 2011 at 11:28 pm

    Great tutorial. Easy to follow along, and to understand. Kudos!

  16. E
    October 29, 2011 at 2:50 pm

    Hello, thanks for your reply via email and Ive unlocked my site http://www.elaineckt.blogspot.com
    I cant seem to move the navigation hover bar to the middle.
    Even after coding , it doesnt work!!

    My html goes:

    #coolMenu,
    #coolMenu ul {
    list-style: none;
    }

    #coolMenu {
    float: left;
    }

    #coolMenu > li {
    float: left;
    }

    #coolMenu li a {
    display: block;
    height: 2em;
    line-height: 2em;
    padding: 0 1.5em;
    text-decoration: none;

    }
    #coolMenu ul {
    position: absolute;
    display: none;
    z-index: 999;
    padding: 0;
    }

    #coolMenu ul li a {
    width: 80px;
    }
    #coolMenu li:hover ul {
    display: block;
    }

    /* Main menu
    ------------------------------------------*/
    #coolMenu {
    font-family: Arial;
    font-size: 16px;
    background: #EF0B0B;
    position: center;
    }
    #coolMenu > li > a {
    font-weight: bold;
    }
    #coolMenu > li:hover > a {
    background: #EF0B0B;
    color: #000;
    position: center;
    }

    text-align: center;

    /* Submenu
    ------------------------------------------*/
    #coolMenu ul {
    background: #EF0B0B;
    }
    #coolMenu ul li a {
    color: #000;
    }
    #coolMenu ul li:hover a {
    background: #EF0B0B;
    }

    Home
    About Us

    Services

    Test
    Test
    Test

    Incorporation
    Contact Us

    Help will be greatly appreciated :)

  17. Jennifer
    November 29, 2011 at 7:02 am

    Hi there,
    I chose not to include the reset.css and added the "padding: 0" instead, which fixed the alignment of the submenu, and love the way this functions in Firefox, but I cannot get it to work in IE (9).

    here's where it's at if you have any suggestions: http://www.aapca3.org

    thank you!

  18. Joey
    December 4, 2011 at 12:54 am

    Hello Sir,

    I wanted to thank you for this article, it was very helpful as it helped me fix issues that I encountered from my understanding of drop down menus.

    I used to have position:relative on the coolmenu li, and position:absolute on the drop down menu. This created an issue where adding long texts in the drop down would not let the second menu to expand, but instead the text will break on the next line. Also, after using position absolute, I had to use a negative margin instead of the positioning property to style the menu according to my needs.

    So an advise for people who may have made the same mistake as I, do not use position:relative on the first li in your drop down navigation lists. It prevents the drop down menu to resize on long text/sentences.

    Also, am not sure if it was caused by the position:relative but, my drop down menu was going transparent on IE 7 before I removed the relative positioning.

    Thanks again for this post.

  19. deep4ut
    December 21, 2011 at 6:26 pm

    thanks for sharing

  20. Luca
    January 12, 2012 at 7:04 am

    Hi,

    I am looking for how to add a submenu in my website.
    I saw your directions and they are really helpful, but I want more help...

    At first, I set up the HTML.
    My code was like this







    And then, accordance with your instructions I changed to







    So, as you can see I add to "but2" the submenu "but8" and "but9".

    Now, the CSS is like this
    #menu{
    background:url(images/menu_bg.jpg) top left no-repeat;
    width:988px;
    height:46px;
    float:left;
    / float:none;
    margin:40px 0 0 0;
    / margin:40px 0 0 3px;
    padding:2px 0 0 4px;
    }
    #menu ul{
    background:url(images/end_menu.gif) top right no-repeat;
    overflow:hidden;
    float:left;
    padding:0 3px 0 0;
    }
    #menu li{
    display:inline;
    list-style-type:none;
    }
    ul#menu_nav
    {
    position:relative;
    float:left;
    width:790px;
    padding:0;
    margin:0;
    list-style-type:none;
    background-color:#000099;
    }
    ul#menu_nav li {float: left;
    margin: 0; padding: 0;
    border-right: 1px solid #555;}

    ul#menu_nav li a.button
    {
    float:left;
    text-decoration:none;
    color:white;
    background-color:#000099;
    padding:0.2em 0.6em;
    border-right:1px solid #CCCCCC;

    font-family: Tahoma;
    font-size: 11px;
    font-style: normal;
    font-weight: bold;
    position: relative;
    height: 21px;
    line-height:1.85em;
    }
    ul#menu_nav li a:hover {
    background-color:#F7F7F7;
    color:#000099;
    border-top:1px solid #CCCCCC;
    }

    ul#menu_nav li span{
    float: left;
    padding: 15px 0;
    position: absolute;
    left: 0; top:25px;
    display: none;
    width: 790px;
    background: #F7F7F7;
    color: #fff;
    }
    ul#menu_nav li:hover span { display: block; }
    ul#menu_nav li span a { display: inline; }
    ul#menu_nav li span a:hover {text-decoration: underline;}
    #menu a{
    display:block;
    float:left;
    }
    .but1{background:url(images/but1.jpg) top left no-repeat;}
    .but2{background:url(images/but2.jpg) top left no-repeat;}
    .but3{background:url(images/but3.jpg) top left no-repeat;}
    .but4{background:url(images/but4.jpg) top left no-repeat;}
    .but5{background:url(images/but5.jpg) top left no-repeat;}
    .but6{background:url(images/but6.jpg) top left no-repeat;}
    .but7{background:url(images/but7.jpg) top left no-repeat;}
    #menu a:hover, .active{
    background-position:bottom left
    }

    So, I don't know WHAT I must ADD to CSS code in order the submenu to work normally.

    Can you help me please to find a solution to my problem?
    Thank you very much in advance!

  21. Gil
    January 19, 2012 at 1:38 am

    Hi. great tutorial. I don't know much about CSS and this helped me understand it, and it's excatly what im looking for. I do have an issue an is that , when I hover over the MAIN MENU LINK the submenu dont appear. They are always showing up no matter if you hover over a link or click or do nothing. Also just below the main there is a div for the rest of the content ect. The sub menu is showing but behind that so you can't really see it

  22. Arjun
    January 23, 2012 at 6:49 pm

    hi Cedric,
    You have done a cool job. I added this menu to my own site.
    Thanks,

  23. CSJ
    January 26, 2012 at 2:39 am

    Great article! But if I'm not mistaken, the "display: block" is not needed, as that's default and you've not set "display: inline" on any of the elements.

  24. CSJ
    January 26, 2012 at 2:45 am

    Sorry, my mistake. Inline is default.

  25. ozogla
    January 28, 2012 at 10:56 pm

    Hi Cedric Ruiz,

    Thanks for the great post. I tried a submenu to the submenu but it didnt work. Please can you help me on this. Thanks.

  26. Hawk
    January 31, 2012 at 11:02 pm

    Don't forget, you can easily convert this into a tab menu by rounding the corners using CSS 3:

    border-top-left-radius:5px;
    border-top-right-radius:5px;

  27. Goran
    February 1, 2012 at 4:20 pm

    Hi,

    First of all thank you for this excellent post.

    I'm just wondering how you can add the possibility to highlight active (selected) menu item tab on first level?

    Thank you in advance.

  28. Brian Borup
    February 3, 2012 at 1:16 am

    Great tutorial. Just what I needed.

    What I need to change in the CSS, to make the submenu aligned to the right, instead of to the left side of the main menu?

  29. Brian Borup
    February 3, 2012 at 1:24 am

    Oh, right-alignment was easy enough.

    Just alter these sections of the CSS:

    #coolMenu > li {
    float: right;
    position:relative; /* NEW */
    }

    #coolMenu ul {
    position: absolute;
    display: none;
    z-index: 999;
    right: 1px; /* NEW */
    }

  30. Greg
    February 7, 2012 at 2:25 am

    With newer versions of jQuery, you should use:

    $(function(){
    $('#coolMenu').child('li').hover(function(){
    $(this).find('ul')
    .removeClass('noJS')
    .stop(true, true).slideToggle('fast');
    });
    });

    • Greg
      February 7, 2012 at 3:26 am

      Correction to myself. I was having a problem of this setup causing a repeating flipping of the toggle when hovering over the menu. I eventually had to do this:

      Remove the display so that default is to allow it to display
      #coolMenu ul {
      position: absolute;

      z-index: 999;
      }

      In the script:
      $(function(){
      $('#coolMenu').children().hover(function(){
      $(this).children('ul')
      .stop(true, true).slideToggle('slow');
      });
      $('#coolMenu > li').children('ul').toggle();

      });
      //This does the same thing, but first toggles the display off naturally. Then the first toggle activated is "on".

      • Jeff
        February 13, 2012 at 4:12 am

        I was having the same problem with the repeating toggle, this fixed it. Thanks!

  31. ajheart
    February 21, 2012 at 6:03 am

    Thanks for the tutorial! You made it very easy to get from A to B and I really appreciate it. One question - how would you configure the code to utilize a sub-level in a list? I mean, make another drop-down FROM a drop-down?

    Thanks!

  32. ajheart
    February 21, 2012 at 6:48 am

    I'm having an issue of a blank space before each menu item, like it's expecting to have a bullet there and it's invisible. This wouldn't be a problem, but it offsets my list to the right about 30px. Any ideas how to fix this? Thanks!

Please note that comments are moderated - and rel="nofollow" is in use. Please no link dropping, no keywords or domains as names. Kindly do not spam, and do not advertise!