Look Ma! No Javascript!

CSS3 drop-down menus

The CSS3 slideshow below only works in Chrome.
Everybody else gets a still image.

The Drop-down menus
HOW TO:

[ For the slideshow, view source ]

We're going to be using CSS3 transitions to make the menus slide down gently, and the background colors fade softly in and out.

This is a barebones multi-level drop down menu made entirely in CSS, that plays nice in all browsers and degrades gracefully to regular CSS2 hover effects in IE.

We're also going to address a couple of typical layout challenges in IE.

The goal of this tutorial is to provide only the most fundamental code necessary for the implementation of the drop-down menu, which can then be used as a template for styling to your heart's content.

[We will not be using the usual display:none, display:block technique, so don't look for it]

Step 1.
Let's set up our html. We're going to put our menu inside a header, and we're also going to create a "content" area below the header.

A little explanation:
This part of the process addresses IE's stacking order, and will ensure that our menu doesn't render behind the Content area, an issue I have seen often. A typical scenario is to have some kind of image scroller under the header, which requires the scroller container to have relative positioning, and causing the menu to render behind the scroller in IE. In order to fix this, our Header MUST must have position:static.

<!DOCTYPE HTML>
<html lang="en">
<head>
<meta  charset="UTF-8" />
<title>CSS3 Horizontal sliding menu</title>
<style>
.header{
	width: 600px; 
	height:50px; 
	border:1px dotted grey;
}
.content{
	position:relative; 
	width: 600px; 
	height:500px; 
	color:white; 
	background-color: #e6056f; 
	overflow:hidden;
	}
.item{
	position:absolute; 
	top:50px; 
	left:20px; 
	width: 600px; 
	height:400px; 
	background-color: grey;
	}
</style>
<body>
    <div class="header">
        <div class="navigation">
        </div>
    </div>
    
    <div class="content">
    	<div class="item">
    	</div>
    </div>

</body>
</html>
                


Step 2.
We're going to use an unordered list to create the menu structure and place it inside the navigation div:
(make sure you replace the #'s with actual links, for example: <a href="#"> becomes <a href="mypage.html">)

            
<ul>
                <li><a href="#">Main - 1</a>
                    <ul>
                        <li><a href="#">Level 2 - 1</a></li>
                        <li><a href="#">Level 2 - 2</a></li>
                        <li><a href="#">Level 2 - 3</a></li>
                        <li><a href="#">Level 2 - 4</a></li>
                    </ul>
                </li>
                <li><a href="#">Main - 2</a>
                    <ul>
                        <li>
                            <ul>
                                <li><a href="#">Level 3 - 1</a></li>
                                <li><a href="#">Level 3 - 2</a></li>
                                <li><a href="#">Level 3 - 3</a></li>
                                <li><a href="#">Level 3 - 4</a></li>
                                <li><a href="#">Level 3 - 5</a></li>
                            </ul>
                            <a href="#">Level 2 - 1</a>
                        </li>
                        <li>
                            <ul>
                                <li><a href="#">Level 3 - 1</a></li>
                                <li><a href="#">Level 3 - 2</a></li>
                                <li><a href="#">Level 3 - 3</a></li>
                                <li><a href="#">Level 3 - 4</a></li>
                                <li><a href="#">Level 3 - 5</a></li>
                            </ul>
                            <a href="#">Level 2 - 2</a></li>
                        <li>
                            <ul>
                                <li><a href="#">Level 3 - 1</a></li>
                                <li><a href="#">Level 3 - 2</a></li>
                                <li><a href="#">Level 3 - 3</a></li>
                                <li><a href="#">Level 3 - 4</a></li>
                                <li><a href="#">Level 3 - 5</a></li>
                            </ul>
                            <a href="#">Level 2 - 3</a></li>
                        <li><a href="#">Level 2 - 4</a></li>
                    </ul>
                </li>
                <li><a href="#">Main - 3</a></li>
                <li><a href="#">Main - 4</a></li>
            </ul>
                


Step 3.
To position the menu horizontally we'll use float:left on the menu items and a couple of basic styles to make it presentable:

      
.navigation {
            width:600px;
        }
        .navigation ul{
        /* positioning */
        	position:relative;
            z-index:1000;
        /* remove the dots next to list items: */
            list-style:none; 
        /* get rid of any default or inherited margins and padding: */
            margin:0; 
            padding:0; 
            
        /* styling: */
            font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
            font-weight: normal;
            font-size: 15px;
        }
        
        /* we're using the direct descendant selectors > to ONLY affect the main menu items */
        .navigation > ul > li {
        /* positioning */ 
            position: relative;
            float: left;
        /* styling: */
            margin-right: 10px;
        }
        .navigation > ul > li > a {
        /* positioning */ 
            display:block;
        /* styling: */
            background-color: #2c2c2c; /*  grey */
            padding:8px 14px;
            text-decoration:none;
            color:#aaaaaa; 
            
        }
        .navigation > ul > li > a:hover{
        /* styling: */
            background-color:#666666; /* grey */
            color:#eeeeee; /* light grey */
        }
                

       
Step 4.
The drop-down boxes. We are going to apply the same styles to secondary and tertiary drop-downs, but you can choose to add additional styles to differentiate them.

       
.navigation ul ul{
            
            background-color:#e6056f; /* remove. this is for illustration purposes only */
            width:340px; /* you need a width to accommodate tertiary menus */
            
            position:absolute;
            z-index:100;
            
            height: 0;
            overflow: hidden;
        }
        

        /* don't display tertiary box yet */
        .navigation > ul > li:hover ul ul, .navigation > ul > li > a:hover ul ul{
            height:0;
            
        }
        /* tertiary drop-down box */
        .navigation ul ul ul{
            left:170px;
            width:170px;
        }
        
        .navigation > ul > li:hover ul, .navigation > ul > li > a:hover ul,
        .navigation ul ul li:hover > ul, .navigation ul ul li a:hover > ul{
            height:220px; /* need a height to accommodate any tertiary menus */
        }
        
        /* drop-down item styles */
        /* if you want different styling for tertiary menus, just copy the 4 rules below and insert an additional ul: for example: ".navigation ul ul li", becomes: ".navigation ul ul ul li" */
        
        .navigation ul ul li{
            background-color:#eaeaea; /* grey */
            width:170px;
        }
        
        .navigation ul ul li:hover {
            background-color:#999; /* grey */
        }
        
        .navigation ul ul li a {
            display:block;
            text-decoration:none;
            margin:0 12px;
            padding:5px 0;
            color:#4c4c4c; /* grey */
        }
        .navigation ul ul li a:hover, .navigation ul ul li:hover > a {
            color:#ffffff; /* white */
        }
                

       
Step 5 - optional
I like to have separator lines between menu items, but only BETWEEN menu items. And I don't want them to go all the way to the edges of the drop-down box either, which means more CSS tweaking, but I think it looks nicer.

Normally we could use :last-child to remove the last line in the list, but since IE doesn't recognize :last-child, we'll use the + selector instead. The following rules insert lines between each menu item, and make sure we don't have any extraneous unwanted lines either. It's a little hairy to get your head around at first, but it works across the board. And since the lines don't go all the way to the edges, it also makes sure there are no weird gaps when you hover over an item.

      
.navigation ul ul ul li a{
            border:0 !important;
        }
        .navigation ul ul ul li + li a{
            border-top:1px dotted #999 !important;
        }
        .navigation ul ul li + li a{
            border-top:1px dotted #999;
        }
        .navigation ul ul li:hover + li a{
            border-top:1px solid #eaeaea;
        }
        .navigation ul ul ul li:hover + li a{
            border: 0 !important;
        }
        .navigation ul ul ul li:hover + li{
            border-top:1px solid #999 !important;
        }
                

       
Step 6.
THE MAGIC


So by now you should have a plain vanilla CSS drop-down menu. Let's add the magic.
It's actually going to be really easy.

Add these properties to the .navigation ul ul rule:

          
-webkit-transition: height 0.3s ease-in;
            -moz-transition: height 0.3s ease-in;
            -o-transition: height 0.3s ease-in;
            -ms-transition: height 0.3s ease-in;
            transition: height 0.3s ease-in;
                


And these, to the .navigation ul ul li rule:

          
-webkit-transition: background-color 0.3s ease;
            -moz-transition: background-color 0.3s ease;
            -o-transition: background-color 0.3s ease;
            -ms-transition: background-color 0.3s ease;
            transition: background-color 0.3s ease;
                

   
Step 7.
Just one more thing if you care about IE 7.

To remove the gaps between menu items in IE 7, I'm going to add some conditional statements into the top of the file:

Replace these two lines
<!DOCTYPE HTML>
<html lang="en">
                

 at the top of your file with this:
<!DOCTYPE HTML>
<!--[if lt IE 7 ]> <html class="ie6" lang="en"> <![endif]-->
<!--[if IE 7 ]>    <html class="ie7" lang="en"> <![endif]-->
<!--[if IE 8 ]>    <html class="ie8" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--> <html lang="en"> <!--<![endif]-->
                


and add this rule to the css:

/* unfortunate ie7 gap fix */
        .ie7 .navigation ul ul li{
            margin-bottom:-3px;
        }
                

   
That's it!

An optional enhancement:
I'm going to add a little arrow to the items that have tertiary menus:

make an arrow.png graphic, and add this rule to your css:
.arrow{background:url(arrow.png) right center no-repeat;}
                
1:
                
 

add the arrow class to the links that have tertiary menus:
ie: <a href="#" class="arrow">Level 2 - 1</a>  

Also, you'll want to remove the background-color in .navigation ul ul. It was meant for illustration purposes only.

Enjoy!

The file is here for your perusal (view source):