Using CSS and HTML to create menus is simple and efficient, as it allows you to build and expand the menu by adding new levels and items easily. In this tutorial, we'll build a three-level rollover menu that expands vertically when the user moves their mouse over the items.

To grasp the ideas presented here you will need some knowledge of HTML unordered lists and CSS

The final outcome we are aiming for is:


Firstly, we need to create some space on the main HTML page to hold the CSS menu.


body {
  margin:  0;
  padding: 5px;
}


#menuContainer {
  background-color: white;
  width: 10em;
  padding: 5px;
}

Notice that we are using "em" to set the width of the container, not px. The reason for this is that if the user chooses to resize the text in their browser, then the size of the elements will change as well to accommodate the text.

This container style will be applied to an HTML <div> element:

<div id ="menuContainer">

Inside this div element we need to put some nested ordered lists to create the structure for our menu. The code below shows the three levels we are going to implement.



<div id ="menuContainer"> 
<ul>
  <li><a href="#">Books</a>
    <ul>
      <li><a href="#">Fiction</a>
        <ul>
          <li><a href="#">Classics</a></li>
          <li><a href="#">Romance</a></li>
          <li><a href="#">Horror</a></li>
        </ul>
      </li>
      <li><a href="#">Non-Fiction</a>
        <ul>
          <li><a href="#">Military</a></li>
          <li><a href="#">History</a></li>
          <li><a href="#">Gardening</a></li>
        </ul>
      </li>
    </ul>
  </li>
  <li><a href="#">DVD</a>
    <ul>
      <li><a href="#">Action</a></li>
      <li><a href="#">Comedy</a></li>
      <li><a href="#">Thriller</a></li>
    </ul>
  </li>
  <li><a href="#">Games</a>
    <ul>
      <li><a href="#">Board games</a></li>
      <li><a href="#">PC games</a></li>
      <li><a href="#">X-Box games</a></li>
    </ul>
  </li>
</ul>




To hide the bullets in the unordered list we set the list-style-type to none and set the margin and padding to 0, relative to the menuContainer to remove any default indentation.


#menuContainer ul { 
  list-style-type: none;
  margin: 0;
  padding: 0;
}

The code below defines the look of the <li> elements and their corresponding links.


#menuContainer li {
  background-color: #CC6600;
  border: 1px solid #FF9933;
  width: 10em;
  /* this is to make the submenus position relative to this li */
  position: relative; 
}

#menuContainer a {
  text-decoration: none;
  color: #FFCC66;
  font-weight: bold;
  font-size: 10pt;
  font-family: Verdana, Arial, sans-serif;
}

Here, we are setting the background, border and width attributes for all <li> elements within the menuContainer. We are also stripping out the default underlines in links and setting our own font attributes.

When the user moves their mouse over an item, we want the background colour, border and the link colour of the item to change. We do this with:


#menuContainer li:hover {
  border: 1px solid #CC6600;   
  background-color: #FF9933;
}

#menuContainer a:hover {
  color: #993300;
}

Next, we want to position the second and third levels of the menu to the right of their parent element using absolute positioning. Note, they will be positioned, relative to their parent <li> item -- we made this work using position:relative when declaring the li style above. Additionally, we want the child nodes to align with the parent node, using top:0. Finally, when we have positioned our elements to our liking, we want to hide them until the user moves their mouse over their corresponding parent items. This can be done by setting the visibility attribute to "hidden", as shown below.


#menuContainer ul ul {
  position: absolute;
  left: 10em;
  top: 0;
  visibility: hidden;
}

You may be wondering if the "#menuContainer ul ul" signifies the second level of the menu only. It may appear to be so, but the style actually applies to all lists that have a parent list element. This means that the style is applied to all the lists but the top level.

Now to the fun part! We want the second and third levels to pop out when the user moves their mouse over their parent <li> elements.


#menuContainer li:hover > ul {
  visibility: visible;
}

Notice that we are using the child selector > for this rule, which is different to the previous rule. Here, we are imposing this rule on the <ul> which is a direct descendant of a <li>. In other words, the <ul> is contained directly within the <li> and is therefore its child element. What this rule basically says is that each <li> element will display only its direct child menu elements.

This code will work beautifully in Firefox and Internet Explorer 7, but the bad news is that if you are using an older version of IE, you will encounter problems. What you will probably notice is that while moving your mouse over the first level items the background colour will not change, nor will the second and third levels of the menu be displayed. This is because older versions of IE do not support the hover property over any HTML element but links. The usage of the child selector (>) is also not supported. So, if you are determined to make this menu work in older, non standards-compliant versions of IE, you will need a workaround.




/*Mouseover: display second level or third level pop-up*/

#menuContainer li:hover ul, #menuContainer li:hover li:hover ul {
  visibility: visible;
}

 

Now, without the child selector when the user hovers over the first level items, both the second and third-level menus will get displayed.


/* Hide third level menu when the mouse is over the first level li*/
#menuContainer li:hover ul ul {
	visibility: hidden;
}


With this rule we are hiding the third-level menu when the second-level menu needs to be displayed.

The above code uses a CSS feature called specificity, which dictates what rule should be displayed when multiple rules apply for the same element. If more than one rule applies for the same element, the one selected will be the most specific one. For example, if we have two rules, "ul ul" and "li:hover ul", and they both apply to a given <ul> element, then the one that is actually used is the more specific, "li:hover ul". The "#menuContainer li:hover li:hover ul" in the code above is the more specific one and tells the third level to display when both the first and the second levels are in hover.

So that takes care of the child selector problem but what about the hovers? Peter Nederlof has made this possible with a handy whatever:hover script . This script uses an IE-specific feature to dynamically attach JavaScript events to those elements that have hover styles. To use the script, you will need to save it to a file called ccshover.htc and reference it in your stylesheet like this:


body {
  margin: 5px;
  padding: 0;
  behavior:url("csshover.htc");
}

To make the menu work across all browsers, you can reference two stylesheets in your HTML page using IE conditional comments.


<!--[if (gte IE 7)|(!IE)]> <!-->
<link rel="stylesheet" type="text/css" href="menu.css" />
<!--<![endif]-->

<!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="menuie6.css" />
<![endif]-->

Now you're all set to use your menu and be confident it will work in any browser. Well, almost. If you've noticed, the menu colours are inverted in Opera and Safari browsers, but I'll leave that to you to look into as a final challenge.

Below are the full working code examples we've used in this tutorial:

HTML | Default CSS stylesheet | IE 6 and below CSS stylesheet

Do you need help with CSS? Gain advice from Builder AU forums

Related links

Comments

1

Ryan Stuart - 06/02/08

The example you have posted (the html link) doesn't work in IE6.

» Report offensive content

2

Ezequiel Muns - 06/02/08

You need to download the files and get the .htc script for it to work in IE6 Ryan.

At least it works fine for me once I do that.

» Report offensive content

3

P&Atilde;&iexcl;draig Brady - 10/02/08

My site uses this technique:
http://www.pixelbeat.org/

I got the implementation from Stu Nichols:
http://www.cssplay.co.uk/menus/flyout2.html

» Report offensive content

4

Rob - 11/02/08

I always find it interesting when someone says "Let's make it work 'cross-browser'" when we really know they mean "This won't work in Internet Explorer". They should just come right out and say "This is a modern technique and only works in modern browsers so, of course, it won't work in IE".

» Report offensive content

5

Regan Rajan - 11/02/08

Yes, I also used the CSSplay script. It worked great on cross browser. The only problem is that we can't set different size for each of the set. All the set and subset but be in one absolute size. It is a disadvantage for myself. But so far, that is the simply script that I found it working great. ReganRajan.com

» Report offensive content

6

JonatasCD - 18/03/08

strange... didnt work in IE 7.. is that normal?!?!

» Report offensive content

7

ash - 29/03/08

Dear Author .
I implemented your solution which doesnt works on my webspage. it has a conflict problem with the existing css file the links are
css file :http://www.kannis.co.uk/style.css
website : http://www.kannis.co.uk/indextempcopy.html

i want to show action , comedy and thriller under why kannis vertical menu .

waiting for your reply - ash2382@gmail.com

» Report offensive content

8

Prefabrik - 12/05/08

Thanks you

thanks you this is using on it page <a href="http://www.prefabrik.tv/index.html">Prefabrik</a>

» Report offensive content

9

Piyush - 23/05/08

Thanks a lot.. it served my purpose :)

» Report offensive content

10

Chris - 29/07/08

This works great for Firefox & IE7, but it dosn't work for IE6.

Please help.

» Report offensive content

11

prefabrik - 26/09/08

12

prefabrik - 26/09/08

thanks http://www.aryol.com.tr

» Report offensive content

Leave a comment

You must read and type the 6 chars within 0..9 and A..F

* indicates mandatory fields.

12

prefabrik - 26/09/08

thanks http://www.aryol.com.tr ... more

11

prefabrik - 26/09/08

thank you ... more

10

Chris - 29/07/08

This works great for Firefox & IE7, but it dosn't work for IE6. Please help. ... more

Log in


Sign up | Forgot your password?

  • Staff XP stays on life support for longer

    This week's Roundup looks at Microsoft's decision to extend the life of Windows XP, the release of Microsoft Surface SDK, Firefox's new Geode plug-in, Yahoo's new tool -- Smush It and more. Read more »

    -- posted by Staff

  • Chris Duckett The good and truly awful celluloid depictions of computers

    Ever wonder why your lawyer uncle leaves the room whenever you turn over to Boston Legal? Or why your forensic science cousin can't stand crime drama? You know the answer: it’s the horrid trivialisation and dumbing down of an occupation to make it appear entertaining. Sometimes it is so unbelievable that it actually hurts and yelling at the screen is the only outlet. Read more »

    -- posted by Chris Duckett

  • Brendon Chase Apple's iPhone engineers to tour Sydney, Melbourne

    Aussie developers will be able to get up close and personal with some of the iPhone engineers in November to learn how to build applications for the platform. Read more »

    -- posted by Brendon Chase

What's on?