This tutorial will explain how to code a perfectly cross-browser compatible, single-level drop-down menu for your website. The first thing you are going to need is a little bit of JavaScript courtesy of Suckerfish. This should be placed in a file called menu.js and saved in the same directory as your html page.

showMenu = function() {
  var subMenuItems = document.getElementById("topMenu").getElementsByTagName("li");
  for (var i=0; i<subMenuItems.length; i++) {
    subMenuItems[i].onmouseover=function() {
      this.className+=" showMenu";
    }
    subMenuItems[i].onmouseout=function() {
      this.className=this.className.replace(new RegExp(" showMenu\\b"), "");
    }
  }
}
	
if (window.attachEvent) window.attachEvent("onload", showMenu);

Now you will need a menu structure, in other words what is actually going to be in your menu. For the purposes of this tutorial, let’s use:

  • Top Link 1
    • Sub Link 1-1
    • Sub Link 1-2
    • Sub Link 1-3
  • Top Link 2
    • Sub Link 2-1
    • Sub Link 2-2
    • Sub Link 2-3
  • Top Link 3
    • Sub Link 3-1
    • Sub Link 3-2
    • Sub Link 3-3
  • Top Link 4
    • Sub Link 4-1
    • Sub Link 4-2
    • Sub Link 4-3
  • Top Link 5
    • Sub Link 5-1
    • Sub Link 5-2
    • Sub Link 5-3

OK, so now you have the structure but how are you going to turn that into an actual menu? This is where the XHTML comes in. Start with a blank XHTML web page as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Single-Level Drop-Down Menu</title>
  </head>

  <body>
  </body>
</html>

Now create a <div> object to place the menu in and give it the id "menu" as follows: <div id="menu"></div> For the menu itself, you can use an HTML unordered list to hold the menu items:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Single-Level Drop-Down Menu</title>
  </head>

  <body>
    <div id="menu">
      <ul>
        <li>
          <a href="#">Top Link 1</a>
          <ul>
            <li><a href="#">Sub Link 1-1</a></li>
            <li><a href="#">Sub Link 1-2</a></li>
            <li><a href="#">Sub Link 1-3</a></li>
          </ul>
        </li>
        <li>
          <a href="#">Top Link 2</a>
          <ul>
            <li><a href="#">Sub Link 2-1</a></li>
            <li><a href="#">Sub Link 2-2</a></li>
            <li><a href="#">Sub Link 2-3</a></li>
          </ul>
        </li>
        <li>
          <a href="#">Top Link 3</a>
          <ul>
            <li><a href="#">Sub Link 3-1</a></li>
            <li><a href="#">Sub Link 3-2</a></li>
            <li><a href="#">Sub Link 3-3</a></li>
          </ul>
        </li>
        <li>
          <a href="#">Top Link 4</a>
          <ul>
            <li><a href="#">Sub Link 4-1</a></li>
            <li><a href="#">Sub Link 4-2</a></li>
            <li><a href="#">Sub Link 4-3</a></li>
          </ul>
        </li>
        <li>
          <a href="#">Top Link 1</a>
          <ul>
            <li><a href="#">Sub Link 1-1</a></li>
            <li><a href="#">Sub Link 1-2</a></li>
            <li><a href="#">Sub Link 1-3</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </body>
</html>

Please note that although you will most likely not be using the top menu items as links, you do still need to give each top menu item an anchor <a> tag in order to use the CSS hover pseudo-class on them. But good old Internet Explorer does not allow hover effects on named anchors, so you will have to use <a href="#"> to make these items links.

So far, so good. But you really need an easier way to tell the top menu items from the sub menu items. This can be accomplished by adding class and/or id names to each <ul> and <li> tag.

Begin by assigning the top-most <ul> tag the id "topMenu" with each topMenu <li> tag that represents a top menu link assigned the class name "topMenuLink". Each nested <ul> tag representing a sub menu will be assigned the class name "subMenu", and finally each <li> tag representing a sub menu link will be assigned the class name "subMenuLink"

By this point your HTML page should look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Single-Level Drop-Down Menu</title>
  </head>

  <body>
    <div id="menu">
      <ul id="topMenu">
        <li class="topMenuLink">
          <a href="#">Top Link 1</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 1-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 1-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 1-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink">
          <a href="#">Top Link 2</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 2-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 2-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 2-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink">
          <a href="#">Top Link 3</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 3-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 3-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 3-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink">
          <a href="#">Top Link 4</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 4-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 4-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 4-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink">
          <a href="#">Top Link 5</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 5-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 5-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 5-3</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </body>
</html>

With that all completed, you should save the file as menu.htm and move on to the final section, the magical CSS file. Creating the CSS style sheet is the next step in creating your drop-down menu, and where you will pull most of your hair out if you're not careful. The first thing you want to do is get the basics out of the way, which consists of general styles that apply to the menu as a whole. So here is your list:

  1. All anchor <a> tags should be displayed as block level items
  2. All list items should have no margin, no padding, and no list item decorations (bullets)
  3. All submenu items need to be hidden until the mouse hovers over the top menu item

Now let's take a look at the CSS required to achieve this:

/* Display all <a> tags as block-level items */
#menu a { display: block; }


/* Set margin and padding to 0px and remove bullets from all list items */
#menu ul { 
  padding:    0px;
  margin:     0px;
  list-style: none;
}

/* Move sub menu items off the screen and out of view until called */
#topMenu li ul {
  position: absolute;
  left:     -999em;
}

/* Display sub menus when the mouse hovers over the top menu item (Used by JavaScript) */
#topMenu li:hover ul, #topMenu li.showMenu ul { left: auto; }

Now you need to get into the specifics of the menu, and some of the things you should know up front are:

  1. How wide will the overall top menu be?
  2. How wide will each top menu item need to be?
  3. How wide will each sub menus need to be?
  4. What color will the top menu background be?
  5. What color will the top menu background be on hover?
  6. What color will the top menu text be?
  7. What color will the top menu text be on hover?
  8. What color will the sub menu background be?
  9. What color will the sub menu background be on hover?
  10. What color will the sub menu text be?
  11. What color will the sub menu text be on hover?
  12. Will your menu items need to have a border around them?

The answers to the above questions are:

  1. How wide will the overall top menu be?
    750px
  2. How wide will each top menu item need to be?
    150px (750px / 5 menus)
  3. How wide will each sub menus need to be?
    150px (The same as the top menu items)
  4. What color will the top menu background be?
    #336666 (shade of green)
  5. What color will the top menu background be on hover?
    #909090 (shade of gray)
  6. What color will the top menu text be?
    #CCCCCC (shade of gray)
  7. What color will the top menu text be on hover?
    #000000 (black)
  8. What color will the sub menu background be?
    #FFFFFF (white)
  9. What color will the sub menu background be on hover?
    #D2D2E1 (shade of blue)
  10. What color will the sub menu text be?
    #000000 (black)
  11. What color will the sub menu text be on hover?
    #000000 (black)
  12. Will your menu items need to have a border around them?
    Yes (this will cause you many headaches)

If you are a perfectionist then the borders will drive you nuts! You can't just put a border around every item, because they will be extra thick where the two borders meet. You also have to account for the width of the border and adjust your menu item widths to accommodate them. And you have to find a cross-browser compatible way to get them all to line up perfectly. That said, there are a few adjustments to be made to the HTML document in order to get your borders right. You need to be able to make changes to the last top menu item and sub menu.

To do this, add the id "lastMenu" to the last top menu anchor <a> tag like so: <a href="#" id="lastMenu">Top Link 5</a> . Also add the id "last" to the last <ul class="subMenu> tag like as follows: <ul class="subMenu" id="last"> .

OK, moving on to the rest of the CSS style sheet and the easiest way to do this is to look at the CSS itself and then explain what each item does:

#menu {
  background-color: #336666;  /* Background color of top menu */
  font-family: Arial, Helvetica, sans-serif;  /* Font used for all menu items */
  font-size: 13px;  /* Font size of all menu items */
  height: 22px;  /* Height of top menu items */
  line-height: 21px;  /* Line height of top menu items (vertically adjust text) */
  margin: auto;  /* Centers menu on page */
  width: 750px;  /* Width of top menu (must be set to center menu on page) */
}


#menu li { float: left; }  /* Display top menu items horizontally from left to right */

#topMenu a { 
  border: 1px solid black;  /* Put border around all menu items */
  border-right-width: 0px;  /* Remove right border from all menu items (to stop double borders between top menu items) */
  text-decoration: none;  /* Remove underline from all menu item links */
  width: 149px;  /* Top menu item width (adjusted from 150px to account for border width) */
}


.topMenuLink a {
  color: #CCCCCC;  /* Set color of top menu text */
  font-weight: bold;  /* Make top menu text bold */
  text-align: center;  /* Center top menu text in menu button */
}

.topMenuLink a:hover {
  background-color: #909090;  /* Set top menu rollover background color */
  color: #000000;  /* Set top menu rollover text color */
}

.topMenuLink a#lastMenu { 
  border-right-width: 1px;  /* Add right border to last top menu item */
  width: 148px;  /* Adjust last top menu item width to fit within top menu */
}

.subMenu {
  background-color: #FFFFFF;  /* Set the background color of the sub menus */
  border-right: 1px solid black;  /* Add the right border back to the sub menus */
  width: 150px;  /* Set the width of the sub menus */
}

.subMenu a {
  color: #000000;  /* Set the font color of the sub menu items */
  font-weight: normal;  /* Return the font weight to normal for sub menu items */
  height: 20px;  /* Set the height of the sub menu items */
  line-height: 20px;  /* Set the line height of teh sub menu items (for vertical alignment) */
  margin-top: -1px;  /* Set the top border of each sub menu link to -1px to remove double borders */
}

.subMenu a:hover {
  background-color: #D2D2E1;  /* Set sub menu rollover background color */
  color: #000000;  /* Set sub menu rollover text color */
}

.subMenu#last { width: 149px; }  /* Adjust width of last sub menu to align right border correctly */

.subMenu#last a { width: 148px; }  /* Adjust width of links in last sub menu to display right border on rollover */

Save the CSS style sheet as menu.css and put it all together. The final menu.js file should contain the following:

showMenu = function() {
  var subMenuItems = document.getElementById("topMenu").getElementsByTagName("li");
  for (var i=0; i<subMenuItems.length; i++) {
    subMenuItems[i].onmouseover=function() {
      this.className+=" showMenu";
    }
    subMenuItems[i].onmouseout=function() {
      this.className=this.className.replace(new RegExp(" showMenu\\b"), "");
    }
  }
}
	
if (window.attachEvent) window.attachEvent("onload", showMenu);

And your final menu.css file should look like this:

/* Display all <a> tags as block-level items */
#menu a { display: block; }

/* Set margin and padding to 0px and remove bullets from all list items */
#menu ul { 
  padding:    0px;
  margin:     0px;
  list-style: none;
}

/* Move sub menu items off the screen and out of view until called */
#topMenu li ul {
  position: absolute;
  left:     -999em;
}

/* Display sub menus when the mouse hovers over the top menu item (Used by JavaScript) */
#topMenu li:hover ul, #topMenu li.showMenu ul { left: auto; }

#menu {
  background-color: #336666;  /* Background color of top menu */
  font-family: Arial, Helvetica, sans-serif;  /* Font used for all menu items */
  font-size: 13px;  /* Font size of all menu items */
  height: 22px;  /* Height of top menu items */
  line-height: 21px;  /* Line height of top menu items (vertically adjust text) */
  margin: auto;  /* Centers menu on page */
  width: 750px;  /* Width of top menu (must be set to center menu on page) */
}

#menu li { float: left; }  /* Display top menu items horizontally from left to right */

#topMenu a { 
  border: 1px solid black;  /* Put border around all menu items */
  border-right-width: 0px;  /* Remove right border from all menu items (to stop double borders between top menu items) */
  text-decoration: none;  /* Remove underline from all menu item links */
  width: 149px;  /* Top menu item width (adjusted from 150px to account for border width) */
}


.topMenuLink a {
  color: #CCCCCC;  /* Set color of top menu text */
  font-weight: bold;  /* Make top menu text bold */
  text-align: center;  /* Center top menu text in menu button */
}

.topMenuLink a:hover {
  background-color: #909090;  /* Set top menu rollover background color */
  color: #000000;  /* Set top menu rollover text color */
}

.topMenuLink a#lastMenu { 
  border-right-width: 1px;  /* Add right border to last top menu item */
  width: 148px;  /* Adjust last top menu item width to fit within top menu */
}

.subMenu {
  background-color: #FFFFFF;  /* Set the background color of the sub menus */
  border-right: 1px solid black;  /* Add the right border back to the sub menus */
  width: 150px;  /* Set the width of the sub menus */
}

.subMenu a {
  color: #000000;  /* Set the font color of the sub menu items */
  font-weight: normal;	  /* Return the font weight to normal for sub menu items */
  height: 20px;  /* Set the height of the sub menu items */
  line-height: 20px;  /* Set the line height of teh sub menu items (for vertical alignment) */
  margin-top: -1px;  /* Set the top border of each sub menu link to -1px to remove double borders */
}

.subMenu a:hover {
  background-color: #D2D2E1;  /* Set sub menu rollover background color */
  color: #000000;  /* Set sub menu rollover text color */
}

.subMenu#last { width: 149px; }  /* Adjust width of last sub menu to align right border correctly */

.subMenu#last a { width: 148px; }  /* Adjust width of links in last sub menu to display right border on rollover */

The final step of this tutorial is to call both the menu.js and menu.css files from your HTML document by adding the following code between the <head> and </head> tags:

<link type="text/css" rel="stylesheet" href="menu.css" />
	<script type="text/javascript" src="menu.js"></script>

Oh, and you can also add a little title text to the page, and the final, final HTML document will then look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>Untitled Document</title>
    <link type="text/css" rel="stylesheet" href="menu.css" />
    <script type="text/javascript" src="menu.js"></script>
  </head>
	
  <body>
    <h1 style="text-align: center">CSS SINGLE-LEVEL DROPDOWN MENU</h1>
    <h3 style="text-align: center">Courtesy of: Frank Jamison</h3>
    <div id="menu">
      <ul id="topMenu">
        <li class="topMenuLink"><a href="#">Top Link 1</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 1-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 1-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 1-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink"><a href="#">Top Link 2</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 2-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 2-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 2-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink"><a href="#">Top Link 3</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 3-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 3-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 3-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink"><a href="#">Top Link 4</a>
          <ul class="subMenu">
            <li class="subMenuLink"><a href="#">Sub Link 4-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 4-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 4-3</a></li>
          </ul>
        </li>
        <li class="topMenuLink"><a href="#" id="lastMenu">Top Link 5</a>
          <ul class="subMenu" id="last">
            <li class="subMenuLink"><a href="#">Sub Link 5-1</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 5-2</a></li>
            <li class="subMenuLink"><a href="#">Sub Link 5-3</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </body>
</html>

Erm, when you say "Cross Browser Compatible", don't suppose you could list which Browsers and O/S's it is compatible with... (Horizontal parent with Vertical Child Drop-downs seem the most difficult and Browser stuffable Menu to date :()

Of course, if you know it works, then I'll take it!
;)

Thanks for this easy to follow tutorial!

okay -still no reply to the browers...
Does it work on Opera, what about Konqueror etc. ?

Additioanlly - that is fine for Fixed Width - what about those of us that build Dynamic sites... with no idea as to what page will be added, the length of the ames etc.... and what happens when text sizes are increased?
if the menu links wrap rows... what happens then ?


Still, most impressive and useful tutorial.

Is it possible to use images with the menu?

hi,
i read your tutorial ,its really usefull . iam wroking on a project which also requires this funtionality but is creating problems with opera.