Pure CSS Menu With Infinite Sub Menus Tutorial

Today we are going to cover how to build a pure CSS menu with infinite sub menus; an area of CSS that is seldom talked about, poorly written or misconceived. This pure CSS menu with infinite sub menus technique makes use of CSS2 selectors so it will not work in IE6 and below without help from JavaScript. With that said, this pure CSS menu with infinite sub menus technique will work in:

  • IE7, IE8,
  • FireFox,
  • Safari
  • Opera

This pure CSS menu with infinite sub menus technique only uses 10 CSS rules making it EXTREMELY light weight. This technique also overcomes some funky IE bugs such as Ghost Hovers and Z-Indexing issues via pure CSS.

 

Preview the example:

Lets Begin shall we? Start by creating a new html document and use the following code to make this lesson go smoother for everyone.

xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Devin R. Olsen - Pure CSS Menu Infinite Sub Menus</title>
</head>

<body>
</body>

In the body of our newly created document lets setup an unordered list with some list items like so.

<ul id="nav">
    <li>Menu 1</li>
    <li>Menu 2</li>
    <li>Menu 3</li>
    <li>Menu 4</li>
</ul>

We start by giving our top-level un-ordered element an id of “nav” so we have some sort of unique identifier to reference to with our CSS. Next lets copy the whole thing and nest a second list into any of our first level list items and change its ID to a CLASS like so:

<ul id="nav">
    <li>Menu 1
        <ul class="nav">
            <li>Menu 1</li>
            <li>Menu 2</li>
            <li>Menu 3</li>
            <li>Menu 4</li>
        <ul>
    </li>
    <li>Menu 2</li>
    <li>Menu 3</li>
    <li>Menu 4</li>
</ul>

That’s it for the HTML portion, just note that top-level list menu gets an id called “nav” while all nested sub menus get a class called “nav”. You can continue to nest as many menus you like in the same manner from here on out to meet your css menu desires.

Lets move onto the CSS portion. In the header of our document lets create some style tags that will house all our menus CSS like so:

<style type="text/css">

</style>

We will start with our most important reset and structure styles for our menu. First lets point to our #nav, .nav and #nav .nav li elements and reset their margin’s and padding’s to zero like so:

#nav, .nav, #nav .nav li { margin:0px; padding:0px; }

This is done to remove any default browser margin’s and padding’s automatically applied to these element types. Next lets point directly to our first level list items and give them some structure / style like so:

#nav, .nav, #nav .nav li { margin:0px; padding:0px; }
#nav li {float:left; display:inline; cursor:pointer; list-style:none; padding:0px 10px 0px 10px; border:1px #000 solid; position:relative;}

Our menu will be of horizontal so we set the first level list items to a float of left and a display of inline. We also give the list items a list-style of none to remove browser default bullet points next to each list item. Last we give our list items a position of relative in order to prevent any child elements who may be positioned absolute from breaking out of the flow of design. The rest of the styles are of visual preference and up to the developer to change however they desire.

Next we must have some way to identify our top-level sub menus to from all the rest. We do this to give visual guidance on how our first level sub menu is displayed against our top-level menu. To do this we must include a new class to our first level sub menus ONLY, called “first” like so:

<ul id="nav">
    <li>Menu 1
        <ul class="nav first">
            <li>Menu 1</li>
            <li>Menu 2</li>
            <li>Menu 3</li>
            <li>Menu 4</li>
        <ul>
    </li>
    <li>Menu 2</li>
    <li>Menu 3</li>
    <li>Menu 4</li>
</ul>

Again this is only for our “FIRST LEVEL SUB MENUS” that we apply this new “first” class to and not any of the rest of our further nested menus. Next lets point to these first level sub menus and set some structure rules via CSS like so:

#nav, .nav, #nav .nav li { margin:0px; padding:0px; }
#nav li {float:left; display:inline; cursor:pointer; list-style:none; padding:0px 10px 0px 10px; border:1px #000 solid; position:relative;}
#nav li ul.first {left:-1px; top:100%;}

We give our first level sub menu’s a top percentage of 100 to make it fall directly below our top-level menu. Because our list items have a 1px border we give our first level menu items a left style that is negative 1 to assure our first sub menu’s fall completely to the left when being displayed.

Next lets start giving our elements some style rules. First we will point to all our list items and anchor links that any list item may carry like so:

li, li a {color:#000;}

Here we have set our list items and anchor tags any list item may carry to have a text color of black or rather #000. Next we will point to all our sub menu list items ONLY and give some structure and styles like so:

li, li a {color:#000;}
#nav .nav li { width:100%; text-indent:10px; line-height:30px; margin-right:10px; border-top:1px #000 solid; border-bottom:1px #000 solid; border-left:none; border-right:none; background:#fff;}

Note how we first pass through the #nav element before calling .nav li vs. just stating .nav li? This is important as its a fix to helps us over come some spacing issues due to our list item borders. The first style we give here is a width of 100% to insure our list items will completely span across its parents set width. The rest of the styles are up to the developer to change to however they like.

Next lets give some structure to our list item’s anchor elements like so:

li, li a {color:#000;}
#nav .nav li { width:100%; text-indent:10px; line-height:30px; margin-right:10px; border-top:1px #000 solid; border-bottom:1px #000 solid; border-left:none; border-right:none; background:#fff;}
#nav li a {display:block; width:inherit; height:inherit;}

We first point to all our list items and then search for all anchor tags, then we give each anchor tag a display of block and an inherited width and height from its own parent element.

Next lets begin adding our menus behavior styles such has hover and when to display a sub menu and when not to display a sub menu. This part is really where the magic happens and our ability to have a pure CSS menu with infinite sub menus come into play.

First we need to give our sub menus a rule to hide them self’s from view until told otherwise like so:

ul.nav { display:none; }

We add an extra measure of security here when dealing with the display none style by stating “ONLY un-ordered list elements who have a class of “nav” must by default be a display of none”.

Next we will set our behavior color styles for list items and list item anchor tags like so:

ul.nav { display:none; }
#nav li:hover > a, #nav li:hover { color:#fff; background:#000; }

We first point to all our list items that are under a hover state, as well as all list item’s anchor tags while the list item is under a hover state. Then we set a text color of white or rather #fff and a background of black or rather #000. These styles are for the developer to change to their desired look and feel.

Next we must create a rule to display our sub menus when its parent list item is under a hovered state like so:

ul.nav { display:none; }
#nav li:hover > a, #nav li:hover { color:#fff; background:#000; }
li:hover > .nav { display:block; }

Here we are stating that all list items that are under a state of hovered who have a child element with the class of .nav (our sub menu) must be displayed. By using the CSS child selector (>) we are also stating that only the first proceeding child sub menu must be displayed while all the rest remain hidden.

Next lets talk about how we fix yet another IE bug. This one is called the “IE:Hover Ghost Bug” and in its basics it leaves deeply nested sub menus in a state of constant display after being hovered. To fix this bug we simply look at our last style as a igniting point. By giving style and structure to our sub menus when told to be displayed, vs. having a constant rule that is always giving style and structure to our element at all times, we squash the IE bug. So we add the following styles to our last rule like so:

ul.nav { display:none; }
#nav li:hover > a, #nav li:hover { color:#fff; background:#000; }
li:hover > .nav { display:block; position:absolute; width:200px; top:-2px; left:50%; z-index:1000; border:1px #000 solid;}

The position absolute is crucial to allowing our sub menus to be positioned relatively to its parents location on the page. We also set a pre-defined width to our sub menus of 200px as well as offset the menu by top -2px (due to borders width) and by left 50% of its parent element. Last and most important style we give to our sub menus is a z-index of 1000 to make sure everything layers or rather sorts correctly.

Last thing we need to do is squash yet another IE bug that deals width z-index and properly sorting elements or rather layers. To do this we simple state that all sub menu’s parent elements (list items) must have a higher z-index value than the sub menu elements like so:

ul.nav { display:none; }
#nav li:hover > a, #nav li:hover { color:#fff; background:#000; }
li:hover > .nav { display:block; position:absolute; width:200px; top:-2px; left:50%; z-index:1000; border:1px #000 solid;}
li:hover { position:relative; z-index:2000; }

Pssst.. That’s it folks, that’s all the CSS you need to have a fully compleated Pure CSS Menu with infinite amounts of sub menus, enjoy!

Completed CSS Code:

#nav, .nav, #nav .nav li { margin:0px; padding:0px; }
#nav li {float:left; display:inline; cursor:pointer; list-style:none; padding:0px 10px 0px 10px; border:1px #000 solid; position:relative;}
#nav li ul.first {left:-1px; top:100%;}

li, li a {color:#000; text-decoration:none;}
#nav .nav li { width:100%; text-indent:10px; line-height:30px; margin-right:10px; border-top:1px #000 solid; border-bottom:1px #000 solid;
border-left:none; border-right:none; background:#fff;}
#nav li a {display:block; width:inherit; height:inherit;}

ul.nav { display:none; }
#nav li:hover > a, #nav li:hover { color:#fff; background:#000; }
li:hover > .nav { display:block; position:absolute; width:200px; top:-2px; left:50%; z-index:1000; border:1px #000 solid; }
li:hover { position:relative; z-index:2000; }

Preview the example.

Thanks Everyone.
Devin R. Olsen

48 Responses to “Pure CSS Menu With Infinite Sub Menus Tutorial”

  1. Farhan Fayyaz says:

    Menu bar is the standard feature of most windows applications. The main purpose of the menus is for easy navigation and control of an application. Some of the most common menu items are File, Edit, View, Tools, Help and more. Each item on the main menu bar also provides a list of options or in the form of a pull-down menu. When you create a Visual Basic 6 program, you need not include as many menu items as a full fledge Windows application such as Microsoft Words.

    http://www.handycss.com/css-menus/creating-menu-with-sub-menu-below/

  2. Bao Ve says:

    i do exactly like that and it run very well. Thank you!

  3. planetjane414 says:

    Thank’s for this useful tutorial.
    Now, I understand clearly on how to manipulate the child menus.
    Thank’s alot!:)

  4. [...] 39. Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  5. Graham Bonham says:

    In a comment awaiting moderation, I see I was mixing up HTML and CSS in commenting on my unfamiliarity with the greater than sign in an HTML file, which could be confused with an unmatched closure of an angle bracket pair. This greater than sign actually occurred in a CSS file. I have now found some additional resources on the various CSS selectors including the greater than sign:
    http://www.456bereastreet.com/archive/200509/css_21_selectors_part_1/
    http://css.maxdesign.com.au/selectutorial/tutorial_step1.htm

    As for navigation bars which wrap if the display/window is too narrow, my gut reaction was that they look awful, though I’d now concede that they sometimes don’t look so bad if they have no coloured background.

  6. Graham Bonham says:

    In my immediately preceding post (at the time of writing, awaiting moderation), I noticed some text was misinterpreted as a long HTML tag and filtered out.

    The text:

    “I assume there is a missing ”

    got through but the text

    “[open angle bracket] before xmlns=”http://www.w3.org/1999/xhtml”[close angle bracket]”

    did not.

    I did not notice whether any other text was stripped out.

    I think I have seen at least one posting by another person which could not be understood fully, presumably because some text had been stripped out in this way.

  7. Graham Bonham says:

    Very nice functionality and easy to copy and paste code to make new menu levels.

    Besides working in the named browsers, it also seemed to me to work fine in Google Chrome (from just a quick look).

    I assume there is a missing

    I was interested in seeing how this copes with long submenu items and found that wrapping does happen if the pixel width exceeds that specified in the li:hover > .nav line. However, I thought that the chosen pixel width looked reasonable in practice and I confirmed that I could increase the pixel width here if I really wanted to cater for unusually long submenu items.

    Personally, I would want to set some font characteristics for #nav so that the navigation bar was displayed in a specified font, rather than the particular browser’s default font. I’m very conscious of IE9, at least as configured on my PC, displaying in a significantly bigger font than Firefox 10 does and, if the browser’s default font is used, there is a risk that longish submenu items which don’t wrap in Firefox 10 might wrap in IE9. I am only a beginner and it might turn out that this potential problem is not so easily fixed as I think. Besides, maybe setting a font is omitted, in the context of a tutorial, for the sake of simplicity.

    I wonder if there is a way to prevent wrapping of the navbar on a narrow display/in a non-maximised window, so as to force the user to scroll to see the end of the navbar. I know that’s not a good solution – and think some would be appalled by such a design – but, personally, I think I’d prefer this to a navbar which wrapped over several lines. I found an interesting piece “Designing navigation for narrow screens” at http://leonpaternoster.com/2012/01/mobile-navigation/.

    Still on the theme of unusually long submenu items, I wonder if it is easily attainable to make the screen automatically scroll to accommodate the display of many levels of long submenu items – AND … to automatically scroll back when the menu levels are hidden again!

    Another possibility might be to make adjustments to the left position of the various submenu levels to try to enable all levels to fit in the available screen space, though this approach has limits which the scrolling approach (if it’s possible to implement that) does not.

    I don’t really think I can make a case which would justify the extra effort and complexity of implementing one of the above but I note the existence of a limit to the number of menu levels which can be displayed and that number will vary depending on the widths allocated to submenu items.

    I was curious to see lines including the character > other than as part of an angle bracket pair.

    I see that
    #nav li:hover > a, #nav li:hover { color:#fff; background:#000; }

    is explained as

    “We first point to all our list items that are under a hover state, as well as all list item’s anchor tags while the list item is under a hover state. Then we set a text color of white or rather #fff and a background of black or rather #000.”

    This usage is new to me. I occasionally try to write filter type programs to read HTML files and write modified output, passing text in angle bracket pairs through unchanged. Finding that correctly written HTML code can include what looks like an unmatched close angle bracket is not so much a concern as it would be to find correctly written code including what looked like an unmatched open angle bracket (as an unmatched open angle bracket would result in the rest of the file being passed through unchanged).

    I wonder whether < also exists in HTML outside of an angle bracket pair.

  8. @ebru, I removed your code from the comment. I normally don’t even allow comments who just spam their code in them, because I have already stated above (at the end of the tutorial) to PLEASE send all code related questions to http://www.jsfiddle.net/. This prevents my comments list from being spammed with meaning less code and keeps the question first and foremost.

    Try again.

  9. ebru says:

    hey devin!
    i was wondering if you can show how to make the second sub menu go horizontal?
    thanks!

  10. ebru says:

    hey there!
    thanks for the helpful tutorials! i changed some of the stuff. and it is working perfectly fine. however, i have been trying to make the second sub menu go horizontal but so far no luck… i was wondering if you can take a look at my code…

  11. murad says:

    Wow That’s cool. thanks

  12. [...] Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  13. Gert says:

    I now see that the code influences other codes that make use of

    After I left out the following line all was OK, both for my old as well as your code:
    /* li:hover { position:relative; z-index:2000; } */

    But I have no clue what further consequences this has. Could you elaborate on this?
    Thanks!

  14. Gert says:

    Hi, thanks for the code.
    Works like a charm, still need to understand the details, but have adjusted it to my needs already. Wonder how it looks like in IE5 or so.

  15. Govind says:

    Thanks, Its nicely explained and easy to implement

  16. [...] 39. Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  17. Nhut Le says:

    Hi Devin,

    Just wanted to say that your tutorials are extremely well written and easy to fully and understand.

    Keep up the excellent work, you are a god-send.

    Cheers, Nhut

  18. Lam says:

    Great job. I’ve edited it to match my design.
    Thank you very much, Devin!
    Have a nice day.

  19. @Adam, I’m not fully understanding the request. Are you looking for more information regarding on how to best use CSS media queries, or very specifically CSS menus for mobile devices? This tutorial’s CSS techniques should already be working for mobile devices as far as I have seen. I will be more than happy to help with a tutorial, I just need more direction in what you or anyone else is looking for.

  20. Adam says:

    I found this website by searching CSS tutorials for mobile sites. Hmmm…??? If you know and I`m sure you do, can you make short tutorial about developing css style for mobile (smartphone) devices?
    Below is link to amazing mobile sites design based mostly on css. The only problem or rather confusion I have is how to apply css for mobile sites. I can do using tables and html, and it works great but as we know there is limit and it might be too heavy.
    http://www.mobileawesomeness.com/

  21. Blogon says:

    Your blog is unique, the website is good information This was a excellent piece of writing. Do go on as you are.

  22. [...] 39. Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  23. kirstie says:

    A simple and a reliable tutorial. A tutorial giving fine output aspects. Appreciate it :)

  24. carrie says:

    I was looking for a simple menu like this so i could tweak it when needed. Thanks

  25. [...] 39. Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  26. [...] 39. Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  27. Donald Kerr says:

    Is there a way to also make the sub-menu horizontal?

  28. mima says:

    hi there, thank you for this tutorial.
    what about IE6 ?
    any help ? please

  29. GE says:

    Love this tutorial, but the menu is left-aligned. What can I do to center the menu?

  30. Mccayde says:

    Fell out of bed feeling down. This has brgtihneed my day!

  31. siri says:

    hi sir
    how r u?
    ur menu’s tutorial with purely CSS is excellent sir
    if possible mail me sir

  32. KLC says:

    Thank you, this is a great tutorial.

    How can you ensure that the sub-menus (when the menu is contained in a header div, for example) fall in front of a following content div as opposed to behind it (I am not referring to Flash elements, just content divs).

    Thanks again.

  33. [...] Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  34. Charlie Sheather says:

    Thanks a lot man, just used this to help me to create a pure css infinite drop down that is dynamically pulled from a database. Although I am sure you are more than capable, If you would like my code and db structure, email me :)

    Cheers
    Charlie

  35. [...] 13. Pure CSS Menu With Infinite Sub Menus Tutorial [...]

  36. Lynn Swangin says:

    Very well written and presented. Logical and easy to follow. Thank you for sharing your knowledge.

  37. [...] [IF YOU WANT AN INFINITE AMOUNT OF SUB MENUS PLEASE REFER TO THIS TUTORIAL.] [...]

  38. Kasi Dato says:

    Hello,Your blog is unique, the website is good information This was a excellent piece of writing. Do go on as you are. Thanks again.

  39. TJB says:

    Thank You for sharing Devin!
    You’re a wonderful teacher.

  40. Assaad Abou-Rached says:

    Killer code! One of the best and most perfect CSS code I have came across!! I’m amazed, keep up the great work buddy

    4/4

  41. slimjim says:

    Just coupled this with a PHP looping round a database table for menus.

    I now have an infinity set of menus, pulled from a VERY simple table. Which makes it truly dynamic.

    Top stuff! Thanks for the help!

  42. Milama says:

    I will try to get it!

  43. It’s fine to check out online sites with material and many thanks for the share which you’ve got done. Generally, I’m quite amazed, but etc…

  44. Adam says:

    Over all I really like this menu, but I have a small problem. In IE 7 you end up with at the third level of the menu at times a empty blue box that shows up when it should not be up at all(there is not ul). Have you encountered this or found a fix for it?

  45. Chuviy says:

    it was very interesting to read your articles!
    I want to quote your post in my blog. It can?
    And you et an account on Twitter?

  46. Isaura Ailor says:

    That is a fantastic post, but I was questioning how do I subscribe towards the RSS feed?

  47. Liaispgic says:

    I liked reading your blog ~ thanks for posting such useful content.

  48. CNA Practice Test says:

    found your site on del.icio.us today and really liked it.. i bookmarked it and will be back to check it out some more later

  49. Valda Nush says:

    An associate of mine told me to check out your blog. This is just the kind of information I was hunting for. I wish I have come across your website earlier.

  50. sythilivy says:

    I liked reading your blog ~ thanks for posting such good content.

  51. rehabilitasyon says:

    Hi, I’m beginning to learn css program. Write your thank you letter will help me a lot of work.

  52. Xuj says:

    Thank you very much for this tutorial!This is totally awesome! ~:->

  53. Kyle says:

    I love you! This is awesome!

  54. Anthony Shireman says:

    I’d swear that it can’t be this easy… but you just proved that it is! You really make pure CSS menus and sub-menus a snap.

  55. Brian says:

    Great Job man! I don’t believe you can make learning infinite menus with css any easier to understand. Bookmarked!

  56. Yogendra Mishra says:

    Hey Devin,

    Its really nice tutorial and very much helpful. I am sure that in future too you will help us in such manner. Once again thanks for it…

    Yogi

  57. I always enjoy feedback from my readers!

Leave a Reply