Pure CSS Horizontal Menu

Today I want to break down the steps of creating a pure CSS horizontal navigation menu. You see a lot of sites using them and while some are very creative, others are way off base as far as functionality is concerned. So without further ado, let’s begin to create a horizontal navigation menu.

Here is our blank document we will use and reference to throughout this tutorial:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Untitled Document</title>
    </head>

    <body>
    </body>
</html>

Let’s start off by creating a container for our navigation by using a div box. I will give my div box an id of “navigation”, but you can name it whatever you like as long as it corresponds to our CSS that we will write here in a second.

<body>
	<div id="navigation"></div>
</body>

Ok now that we have a simple container for our navigation links, we can begin to add some style rules.
Let’s start styling our navigation container by giving it a width, height and background color.

#navigation{
    width:100%;
    height:30px;
    background-color:#999;
}

If you are unfamiliar with writing CSS, I strongly suggest you read up on some CSS basic tutorials.

So let’s look at what we have done to our container.

fig1

Nothing special looking yet, but we now have our container setup to move forward in creating our navigation menu.
Now let’s add our menu items to our navigation container by using the unordered list method. Go back to our navigation container and add the following.

<body>
    <div id="navigation">
        <ul>
	    <li>Menu Item 1</li>
	    <li>Menu Item 2</li>
	    <li>Menu Item 3</li>
	    <li>Menu Item 4</li>
        </ul>
    </div>
</body>

Here is what our navigation menu should look like now.

fig2

You might be wondering how this is going to be a horizontal menu when our list items are ordered like a vertical menu. Well we still need to create a few more rules and styles to turn our menu into a horizontal look.

Go back up to our CSS and add the following rules:

#navigation{
    width:100%;
    height:30px;
    background-color:#999;
}

#navigation ul { }

#navigation ul li { }

(#navigation ul) points to any <ul> in our navigation container.
(#navigation ul li) points to <li> in our navigation container that is a child of <ul>.

Now that we are directly pointing to our <ul> and <li>, lets add some property’s to these guys.
Add these styles to your two new rules:

#navigation ul
{
    margin:0; 
    padding:0;
}

#navigation ul li
{
    display:inline; 
    height:30px; 
    float:left; 
    list-style:none;
}

What we have done here is we first told our <ul> to have a margin and padding to have a 0px.
We do this to remove any browser default margins and paddings that comes along with <ul> tags.

Next we point directly to our list-items and give them styles of display, height, float and list-style. The display and float styles are used align our list items in a horizontal fashion. We also set the height of each list item to 30px to match the height of our over all menu. Lastly is the list-style rule, we set it to none in-order to remove our browser default list-item bullets that come natively with the ordered/unordered lists.

fig3

Great! Now we are on track to creating a horizontal menu, but hmm it looks kind of bunched up. Its hard to tell where one menu item starts and another menu item ends.

To space out list items out, lets go back to our CSS rule for our <li> and add a left margin.

#navigation ul li
{
    display:inline; 
    height:30px; 
    float:left; 
    list-style:none; 
    margin-left:15px;
}

Here are our results.

fig4

Much better now, we can clearly see where each menu item starts and ends.

Let’s now turn our menu items into links by adding the following to your menu’s markup:

(We will not worry about where each item links to because this is out of the scope of this tutorial.)

<ul>
    <li><a href="#">Menu Item 1</a></li>
    <li><a href="#">Menu Item 2</a></li>
    <li><a href="#">Menu Item 3</a></li>
    <li><a href="#">Menu Item 4</a></li>
</ul>

Here is the results of each list items text being wrapped around the anchor tag (<a></a>):

fig5

YIKES, that’s just plain ugly looking right?

First, our menu items now have a solid blue color that is standard for all links. Second, each link now has an underline decoration. It’s very common for links to be styled with something more suitable for your sites theme, rather then use browser default styles.

So how do we fix these two issues? We first point to these links in our see by setting up two new rules like so:

#navigation li a { }

#navigation li a:hover { }

Our second rule is a hover rule. Hover rules (pseudo selector) allows us to dictate when the underline should appear below our links.

Here are our rules with their new styles:

#navigation li a
{
    color:#fff; 
    text-decoration:none;
}

#navigation li a:hover
{
    text-decoration:underline;
}

Now our links should have a white font color, but no underline if we are not hovering over them.
If we do hover over links though, then our links should receive a text decoration of underline.

Here are our results:

fig6

Our menu is looking great now, but you might be asking yourself. “Self, what if I want to have sub menu items? How would I go about creating something like that?”

Good question, let’s look at how we can create a sub menu’s for each menu item that is displayed only when a user hovers over our main menu items.

Let’s start to create our sub menu.

<ul>
      <li>sub menu item 1</li>
      <li>sub menu item 2</li>
      <li>sub menu item 3</li>
      <li>sub menu item 4</li>
</ul>

You now might be asking, “Where do we put this second unordered list of sub menu items?”. Well believe it or not we actually put it within each of our main menu items <li>.

Make your code look like the following.

<div id="navigation">
    <ul>
        <li>
        <a href="#">Menu Item 1</a>
            <ul> 
                <li>sub menu item 1</li> 
                <li>sub menu item 2</li> 
                <li>sub menu item 3</li> 
                <li>sub menu item 4</li> 
            </ul>
        </li>

        <li>
        <a href="#">Menu Item 2</a>
            <ul> 
                <li>sub menu item 1</li> 
                <li>sub menu item 2</li> 
                <li>sub menu item 3</li> 
                <li>sub menu item 4</li> 
            </ul>
        </li>

        <li>
        <a href="#">Menu Item 3</a>
            <ul> 
                <li>sub menu item 1</li> 
                <li>sub menu item 2</li> 
                <li>sub menu item 3</li> 
                <li>sub menu item 4</li> 
            </ul>
        </li>

        <li>
        <a href="#">Menu Item 4</a>
            <ul> 
                <li>sub menu item 1</li> 
                <li>sub menu item 2</li> 
                <li>sub menu item 3</li> 
                <li>sub menu item 4</li> 
            </ul>
        </li>
    </ul>
</div>

Let’s look at the results of adding our sub menu items to our overall menu:

fig7

YIKES AGAIN! What happen to our menu, it’s all messed up now? We still have to create a few more CSS rules to get the look we are trying to accomplish.

Before we begin to write our new CSS rules lets think about how the whole thing is set up as far as parent to child elements are concerned.

#navigation -> ul -> li -> ul -> li

We have our navigation container, and its list of menu items. In each menu list item we start another list of menu items. So we need to create CSS rules that point specifically to our sub menu items.

Add the following to your CSS:

#navigation li ul { }

#navigation li:hover ul { }

#navigation li li { }

Here we are setting up rules that say, “if our navigation container list item has a sub unordered list and list items in it, then use these CSS rules”. We are also set up a hover rule so when a user hovers over a first level list item, it will hide or display its child sub menu.

Add these styles to our new rules:

#navigation li ul
{
    margin:0;
    padding:0;
    display:none;
}

#navigation li:hover ul
{
    display:block;
    width:160px;
}

#navigation li li
{
    list-style:none;
    display:list-item;
    width:100%;
}

We set our sub menu <ul> to have a display rule of none to hide our sub menu from the users.

Next we set a hover state to our main menu list items that says, “If a user hovers over any one of our main menu items, then indeed display it’s sub menu to the user”.

Finally we have to style our sub menu items to be listed in a vertical fashion, instead of following its parent’s rule of the horizontal look by setting them to be a display of list-item. Our sub menu items also need to have a width of 100%, this ensures that shorter combinations of link lengths under our fixed width of a sub menu, do not stack side by side, but rather always stack above and below each other.

Let’s see what our results look like now:

fig8

We in fact have our sub menu list items styled correctly, and our sub menu only displays when we hover its parent. The problem we now have, is that the sub menu is not being displayed directly under its hovered parent. We also have no background colors set for our sub menu, this makes it look a little weird and hard to read.

How do we fix these two issues? Well to position our sub menu correctly, we have to go back to our main menu list item’s rule we wrote a while back, and add a position property to it.

So make your main menu list item rule look like the following:

#navigation ul li
{
    display:inline;
    height:30px;
    float:left;
    list-style:none;
    margin-left:15px;
    position:relative;
}

This is preparing our submenu to be positioned absolute, but relative to our main menu items. So now add the a another position style, but this time to our sub menu:

#navigation li ul
{
    margin:0;
    padding:0;
    display:none;
    position:absolute;
}

When giving an element a position absolute, you are breaking the element out of the flow of design and searches for a stopping point in its parents. (hence giving the first level list items a position relative)

We not only have to add a position of absolute to our sub menus, but also a left and top in order to stop the browser from trying to guess where to place our sub menus.

All this left rule is saying is that we want our sub menu to be position left by 0px, and top by 20px to our relatively positioned parent list item:

#navigation li ul
{
    margin:0;
    padding:0;
    display:none;
    position:absolute;
    left:0; 
    top:20px;
}

We also wanted to fix our sub menu’s background color, so let’s add this and make it the same color as our main menu.

#navigation li ul
{
    margin:0;
    padding:0;
    display:none;
    position:absolute;
    left:0;
    top:20px;
    background-color:#999;
}

Let’s again take a look at our results.

fig9

Excellent, we have a great responding sub menu that pops up when you roll over our main menu items! But hey, how come our sub menu items have a font color of black, and they don’t have any text decoration? Well in short, we again need to wrap our sub menu items around anchor tags (<a></a>) and write our last CSS rules.

Make each sub menu’s markup look like the following:

<ul>
   <li><a href="#">sub menu item 1</a></li>
   <li><a href="#">sub menu item 2</a></li>
   <li><a href="#">sub menu item 3</a></li>
   <li><a href="#">sub menu item 4</a></li>
</ul>

And finally, add the following CSS rules and styles:

#navigation li li a
{
    color:#fff; 
    text-decoration:none;
}

#navigation li li a:hover
{
    text-decoration:underline;
}

Here we are pointing specifically to our sub menu links, and saying “If a link is not being hovered, then have no text decoration, if it is being hovered though, then add a text decoration of underline”.

Here are our final results:

fig10

View The Working Example:

And that’s it folks! You have now created a pure horizontal CSS menu that has a pop out sub menus.

This method of a horizontal menu is both cross-browser friendly and also the best method for a SEO approach.

Enjoy! Devin R. Olsen

Devin R. Olsen

Devin R. Olsen

Located in Portland Oregon. I like to teach, share and dabble deep into the digital dark arts of web and game development.

More Posts

Follow Me:TwitterFacebookGoogle Plus

292 Responses to “Pure CSS Horizontal Menu”

  1. Devin R. Olsen Daryl Musashi says:

    Just did some more digging and it is indeed the #navigation li:hover ul{width:160px}. It seems that if you have multiple menu items that don’t reach the maximum width, the ‘s show up on 1 line rather then 2.

  2. Devin R. Olsen Daryl Musashi says:

    Great Tutorial. Just 1 glitch. Have a sub menu that rather then displaying from top to bottom displays side by side (even though all my other menus display top to bottom like I want). I think it has something to do with the width? Any ideas why it wouldn’t work?

  3. Devin R. Olsen Devin R. Olsen says:

    @Shubhank, please be note that to make this horizontal menu work in versions IE5 and IE6 you must use the tutorial up date link at the bottom of the tutorial. In order to bring pseudo hover behavior to these two browser you must use the pseudo hover fix t

  4. Devin R. Olsen Shubhank says:

    Excellent Code , But only one problem is that\” this code is running in fireforx but not in IE\”

  5. Devin R. Olsen Evelyn says:

    Hi Olsen – I really appreciate your nice work. Just a request- is there any way you can come up with a tutorial for this comments/post (just like the one I am using to contact you) displayed on your website. I think this is the easiest and best posting site I have seen.

  6. Devin R. Olsen marlagrodem1@aol.com says:

    Solve it…. Your tutorial gives each of the building blocks .. so I was able to fiqure out that IE, FF, use text-align center and Safari used margin left … so a quick change to margin left … and my submenus are fine thank you again for a wonderful tutorial

  7. Devin R. Olsen marlagrodem1@aol.com says:

    This is the best tutorial. I’ve erased my DW CS3 Spry widgets
    and will create my horizontal menu bars ALWAYS with this method. I have one slight problemo … in Safari the list items are right justified even though I’ve called for text to be centered which it is in IE, FF, and Chrome.
    Suggestions ?
    http://smokeymountaincabinets.com
    here is my navigation info which is called in an external style sheet
    #navigation{
    width:890px;
    height:30px;
    font-size: .9em;
    font-family: Calibria, Verdana, Arial, san-serif;
    text-align:center;
    color: #ffffff;
    background-color: #240055;
    }

    #navigation ul
    {
    margin:0px;
    padding:0px;
    border: 1px solid #CCC;
    }

    #navigation ul li
    {
    display:inline;
    height:30px;
    width:120px;
    float:right;
    list-style:none;
    margin-left:45px;
    position:relative;

    }
    #navigation li a
    {color:#fff; text-decoration:none;}

    #navigation li a:hover
    {color:#ff8040; text-decoration:none;}

    #navigation li ul
    {
    margin:0px;
    padding:0px;
    width:120px;
    display:none;
    position:absolute;
    left:0px;
    top:30px;
    background-color: #240055;
    }

    #navigation li:hover ul
    {
    display:block;
    width:120px;
    }

    #navigation li li
    {
    list-style:none;
    display:list-item;
    }

    #navigation li li a
    {color:#ffffff; text-decoration:none;}

    #navigation li li a:hover
    {color:#ff8040; text-decoration:none;}

  8. Devin R. Olsen Stefan - bulgaria says:

    Thanks a lot! I’ve just waste 1 hour of searching your simple navigation menu over the internet and suddenly find it on YOUR web site! And best of all is that code is written simple and understandable. Cheers!

  9. Devin R. Olsen Devin R. Olsen says:

    Challenge excepted!

    Yes indeed its a very simple transition with what we have here already.

    If we remove position:relative; from \”#navigation ul li\” and for our demo sakes, move it up to the \”#navigation\” rule we can extend our sub menus to the width of the entire menu.

    To do so add a width:100%; to \”#navigation li ul\” rule and change top:20px; to top:30px;.

    Next remove width:160px; from \”#navigation li:hover ul\” rule.

    Last we must display our sub menu items inline of each other so in this \”#navigation li li\” rule change display:list-item; into display:inline; and add a float:left;

    Vola horizontal menu with horizontal sub menu.

  10. Devin R. Olsen mark.stewart@shaw.ca says:

    I like the minimal code.
    But I have a challenge for all.
    How do you make the sub-menus horizontal?
    When you hover a menu item with a sub-menu,
    the drop down sub-menu items display on a horizontal line,
    under the main menu line.
    Stu Nichols at css-play.co.uk calls this appearance the horizontal drop-line menu, but he uses a mass of code to anchor the main menu and the drop-line menus in multiple tables.
    Will the clean code here adapt to the drop-line model?

  11. Devin R. Olsen Devin R. Olsen says:

    Brian L.

    Please make sure you are not using Dreamweaver’s WYSIWYG mode or rather Design mode alone.

    &-n-b-s-p-; space issues only comes from using the space bar as a structural tool for elements. Results will always be skewed for the persuit of full cross browser compatibility and OS by trying to bend your layout around the preview window of Dreamweaver.

  12. Devin R. Olsen Brian L. says:

    Devin, I ended up placing the cursor in the space and hitting backspace. I had tried playing with margins in the ul li with no luck. I really appreciate your help. On a side not (since you really seem to know your stuff) i have a HTML page the breaks between the navigation buttons on the left of the page. Everything is aligned to top. It does not show to be broken in dreamweaver or the macs in my schools computer labs; only on my home computer in firefox and dreamweaver. You can view the pages at http://allbdesigns.com/Main_links/templates.html and particularly hi def images, tires

  13. Devin R. Olsen Devin R. Olsen says:

    @Brian L., try reducing the margin-left:15px; amount in the (#navigation ul li) CSS rule. Let me know if this works out for ya.

  14. Devin R. Olsen Brian L. says:

    Hey Devin, this tutorial has been the most help I have found lately. However, I am still having a problem. I was using the first part of this tutorial to create a horizontal nav bar using images sliced out of photoshop. It does create the horizontal nav bar, but it also creates small spaces between each nav item. Any ideas for eliminating the small extra spaces? Thanks a bunch!

  15. Devin R. Olsen mark.stewart@shaw.ca says:

    We have a centered drop-line menu. The drop-line does not center, but drifts to the right! Any idea how to fix this?
    Here is the xhtml:
    #tryThis{text-align:center;font-size:1em;font-weight:normal;font-family:Verdana, Helvetica, sans-serif;cursor:pointer;}
    .navbar{position:relative;width:100%;}
    .navbar ul li{display:inline;list-style:none;}
    .navbar li ul{display:none;position:absolute;width:100%;top:1em;left:0%;right:0%;}
    .navbar li:hover ul{display:block;}
    .navbar li li{list-style:none;display:inline;}
    .navbar li a, .navbar li li a{text-decoration:none;}

  16. Devin R. Olsen Fernando says:

    Let me say that this was the best and simple I found. You don’t imagine the crap i’ve been seeing for the last couple of days. It really helped me. Thank you very much

  17. Devin R. Olsen Hitomi says:

    OK, now. . . I learned more than I thought I could! Thanks again.

  18. Devin R. Olsen Hitomi says:

    How come my whole comment is not showing??? Anyway, Thank you so much!!

  19. Devin R. Olsen Hitomi says:

    I just wanted to learn how to write a horizontal menu using div

  20. Devin R. Olsen Greg Simkins says:

    Thanks Devin. This is exactly what I was looking for. I will try it out right away! I was able to read and understand this on my iPhone!

  21. Devin R. Olsen Devin R. Olsen says:

    Ok, I have posted a complete tutorial on the vertical navigation menu. Have a look under CSS tutorials up top. Enjoy.

  22. Devin R. Olsen Devin R. Olsen says:

    @Suresh, Why not, seems useful and has been requested more than once. Consider it done and might be up later tonight.

  23. Devin R. Olsen Suresh says:

    Hi Devin, First of all its a very nice tutorial thanks for taking your time to help others. Please could you teach on another tutorial on how to make parent ul to be vertical (Top Nav) and all the child ul to be on the LHS of the page(left nav or Horizontal menu). Many Thanks.

  24. Devin R. Olsen Tarek says:

    oh devin you played up ,i substracted 2 pixels from the 16px

  25. Devin R. Olsen Devin R. Olsen says:

    @Tarek, when you say \”lowered the top pixels position by 2px\” you mean you took 2 pixels away from the top style over all amount right? You didn’t add two more pixels to the top style… if so and its still giving you problems, send me your email throug

Leave a Reply