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 Tarek says:

    Devin i did what you asked me to do : i used the !important then i lowered the top pixels position by 2px, but the problem still exists plz help. if you need the source files just give me a sign

  2. Devin R. Olsen rajan khan says:

    really!…thank you very much!…

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

    Hi Tarek, looks to me like in IE6 your sub menu sits 1 or 2 pixels lower than the pseudo hover likes. Because of this 1 or 2 pixel gap, you will make the pseudo hover rule fall off as it should when you hover off the menu. I suggest that in your #Hnav li ul CSS rule you alter the top style and lower it by a few pixels and see if that helps with the IE6 glitch. Also if you would like to isolate IE6 to only have a lower top value, I would use the !important rule on it. Second, it looks like you are using PNG 24 alpha images here in your header, please refer to this tutorial on how to fix PNG images in IE PNG Alpha Transparency Fix

  4. Devin R. Olsen Tarek says:

    thank’s Devin, unfortunately my h-menu doesn’t work properly in internet explorer 6 .
    plz take a look and tell me what’s wrong with my css file
    http://www.tribaly.com/projets/appma/
    thank’s

  5. Devin R. Olsen Yoda Turbo says:

    Hey Devin, Thanks a lot for this tutorial! It’s content quality, clarity and usefulness is equal to that of the renowned W3Schools.com, and that’s saying something! This one definitely gets a bookmark! Keep up the good work!

  6. Devin R. Olsen vaibhav says:

    thanks forthis tutorial it is a great help for learners like me.

  7. Devin R. Olsen monyuka says:

    best tutorial i’ve ever seen for pure CSS horizontal menu. thanks devin !

  8. Devin R. Olsen Devin R. Olsen says:

    Hi Cat, to make a horizontal sub menu instead of the standard vertical drop down you will need to change just a few styles.

    * First add a position:relative; to your #navigation{} style rule.

    * Second Remove the position:relative; from your #navigation ul li style rule.

    * Thrid Turn top:20px; in to top:25px; in your #navigation li ul style rule.

    * Forth Change the width:160px; to width:100%; in your #navigation li:hover ul.

    * Fifth Turn display:list-item; to be display:inline; and also add float:left; to your #navigation li li style rule.

    Vola a horizontal sub menu.

    Great question CAT.

  9. Devin R. Olsen CAT says:

    WOW..THIS SITE IS AWESOME..the best I have read so far. How do you make your favicon to move and change?? This is so cool! Can you teach me how to do that?

  10. Devin R. Olsen cat says:

    This is far best out of everything I have read on the web!! you are great!! and updates even!!

    One question tho. When I tried to make a submenu, like yours, instead of making a vertical drop down menu. I tried to make a horizontal menu… by giving some width.. but the alignment is really a pain. Can you please let me know if you can show me how I can improve my design.. now I use a way to hide it.. so it look like its working..
    ….still try to solve the problem

  11. Devin R. Olsen HKansal says:

    I am having IE6. The :hover is making the anchors underline, but the sub menus are not coming up. I hope it’s only a prob with IE. Any Suggestions?

  12. Devin R. Olsen Devin R. Olsen says:

    Aj, indeed sub sub menus can be useful and they only require what you have already learned from this tutorial. Simply create a new sub level of CSS rules like you have done for the first sub menu level.

    So instead of:

    #navigation li ul

    #navigation li:hover ul

    #navigation li li

    #navigation li li a

    #navigation li li a:hover

    you would have a new second level of rules like this:

    #navigation li li ul

    #navigation li li:hover ul

    #navigation li li li

    #navigation li li li a

    #navigation li li li a:hover

    The only other changes would have to be in the new sub level rule \”#navigation li li ul\” where you would want to adjust the top and left rules to your desired results.

    Lastly don’t forget to add a new sub level unordered list in our structure where you desire a second sub level menu.

    I was going to write a tutorial on a second sub level but I soon figured if you have studied this tutorial from start to finish you should be able to walk away with knowing to setup a second sub level fairly easily.

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

    Hi SauloA,

    In order to center the menu you must add a few simple styles to our unordered list rule.

    #navigation ul
    {margin-left:auto; margin-right:auto; margin-top:0px; padding:0px; width:470px; text-align:left;}

    We have replaced the margin:0px; with a margin of left right and top. Both left and right are set to auto while top is 0px in order to still remove the unneeded default margin that comes with a unordered list.

    We also have added a set width, now this is important because you cant set an element to be centered with out first declaring its width. For this menu our width is respectively 670px.

    Our last addition to this rule is a text align of left in order to override our next and final addition.

    In IE6 you cant use margin autos without first declaring the element of questions parent node to have a text align of center. So we give our \”#navigation\” rule a text align of center and override it with our text align of left in our unordered list.

    #navigation
    {width:100%; height:30px; background:#999; text-align:center;}

    Hope this helps, and keep the questions coming people don’t be shy!

  14. Devin R. Olsen SauloA says:

    Is there anyway to have the menu centered in the div? I would rather have my menu centered instead of on the left.

  15. Devin R. Olsen Aj says:

    Add a 2 level drop box and that would be tight. good tutorial my man

  16. Devin R. Olsen Craig says:

    This IS amazing! no javascript, wow! Bookmarked!

  17. Devin R. Olsen Devin R. Olsen says:

    @Joe – Hey, glade you liked it. Feedback like this always lifts my spirits especially when I know I have helped yet another individual. Stay tuned for much more to come guys!

  18. Devin R. Olsen Joe says:

    This is amazing!!! I like the way you break it down, it is really easy to follow. I will be returning my cyber friend…thanx alot

  19. Devin R. Olsen Devin R. Olsen says:

    @Yup! Sounds like it might be a useful tutorial. Certainly will but I cant say for sure when I will be done cause I have a lot of them in the works right now. Keep checking back and I will certainly get something up soon.

  20. Devin R. Olsen Yup! says:

    Could you make a tutorial on how to make a pure css vertical navigation menu? Where the menu is on the first of a three column layout? It could help me alot! And nice tutorial btw!

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

    Hi Wondwossen, this is in fact the second time I have been asked to either include this into my menu builder under tools or exstend this totorial and talk about sub menus with in a sub menu. Tonight I will hopfuly be adding to this tutorial and show the best way to setup this horizontal menu with infinite sub menus. stay tuned

  22. Devin R. Olsen Wondwossen says:

    How to create submenu with submenu

  23. Devin R. Olsen Wynand says:

    Thanx for the tut… it’s very helpfull

  24. Devin R. Olsen Devin R. Olsen says:

    I always enjoy feedback from my readers.

Leave a Reply