The first and most important part of creating our menu is the menu structure itself. The best way to do this is to build an unordered list, with each sub-menu appearing as a list within its parent list item. Sound complicated? It’s actually very straightforward:
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">About</a>
<ul>
<li><a href="#">History</a></li>
<li><a href="#">Team</a></li>
<li><a href="#">Offices</a></li>
</ul>
</li>
<li><a href="#">Services</a>
<ul>
<li><a href="#">Web Design</a></li>
<li><a href="#">Internet
Marketing</a></li>
<li><a href="#">Hosting</a></li>
<li><a href="#">Domain Names</a></li>
<li><a href="#">Broadband</a></li>
</ul>
</li>
<li><a href="#">Contact Us</a>
<ul>
<li><a href="#">United Kingdom</a></li>
<li><a href="#">France</a></li>
<li><a href="#">USA</a></li>
<li><a href="#">Australia</a></li>
</ul>
</li>
</ul>
That’s it: some simple HTML that is both accessible and easy to edit.
Visually appealing?
If you have previewed the menu above, you’ll see a pretty boring list of items. And I promised you it would be visually appealing! Let’s add some style.
The first step is to remove the indents and bullets from the unordered list and define the width of our menu items.
ul {
margin: 0;
padding: 0;
list-style: none;
width: 150px;
}
Next, we need to position our list items. Fortunately, these will stack vertically by default, which is what we require. However, we must set the position as relative
, because we will need to position the sub-menus absolutely within them.
ul li {
position: relative;
}
Next step is the sub-menus. We want each sub-menu to appear to the right of its parent menu item when that item is hovered over.
li ul {
position: absolute;
left: 149px;
top: 0;
display: none;
}
Using the “left” and “top” attributes, we can absolutely position each sub-menu within its parent menu item. You will notice I have set the “left” property to 149px (1px less than the width of the menu items), which allows the sub-menus to overlap the main menu and not produce a double border. (You’ll see what I mean later.)
We have also set display to “none,” as we don’t want the sub-menus to be visible by default.
So now we have the framework in place, but it’s still looking a bit plain. Let’s style those links.
ul li a {
display: block;
text-decoration: none;
color: #777;
background: #fff;
padding: 5px;
border: 1px solid #ccc;
border-bottom: 0;
}
I have styled the links to my taste, but they can be changed to your preference, as you wish. It is important to set display to “block,” as we want each link to take up all the available space of its containing list item.
So things are looking a little better, although users of Internet Explorer for Windows may disagree. Unfortunately, IE Win interprets the line breaks between our nicely formatted HTML list items as white space, so you will notice that the menu items don’t stack up neatly in that browser. However, there is a way around IE’s bugs:
/* Fix IE. Hide from IE Mac \*/
* html ul li { float: left; }
* html ul li a { height: 1%; }
/* End */
We can apply the Holly Hack above, which hides these rules from all browsers but IE Win. Perfect. You will notice the height: 1%
rule that has also been added. Unfortunately (again!) the float fix uncovers another IE bug, which requires a height value to make the links display as block-level elements.
You will also notice the need to close the menu, which can be done by adding the missing border to the bottom of the list. So, the ul
rule becomes:
ul {
margin: 0;
padding: 0;
list-style: none;
width: 150px;
border-bottom: 1px solid #ccc;
}
With some luck, everyone should now be able to see the unfunctional menu.
Making it work
Now the fun bit. We need to make those sub-menus appear when we hover over the menu items.
li:hover ul { display: block; }
Voila...here’s the bare bones menu in action.
“Woo hoo! It works!” I hear 1% of you shout. “Awesome!”
OK, OK, so that darn IE/Win has to ruin everything and not do as it’s told. IE/Win only allows the :hover
pseudo-class to be applied to a link — so the li:hover
that makes the sub-menus appear means nothing to IE.
A tiny jot of JavaScript is required to kick IE back into action (line wraps marked » — Ed.):
startList = function() {
if (document.all&&document.getElementById) {
navRoot = document.getElementById("nav");
for (i=0; i<navRoot.childNodes.length; i++) {
node = navRoot.childNodes[i];
if (node.nodeName=="LI") {
node.onmouseover=function() {
this.className+=" over";
}
node.onmouseout=function() {
this.className=this.className.replace»
(" over", "");
}
}
}
}
}
window.onload=startList;
Great thanks and appreciation is due here to Patrick Griffiths and Dan Webb, who introduced this trickery in a previous ALA article, Suckerfish Dropdowns. Thanks, guys!
So, the hover rule now becomes:
li:hover ul, li.over ul {
display: block; }
Additionally, we also need to associate the JavaScript with our main ul
, which becomes:
<ul id="nav">
Hopefully, with the above tweaks in place, everyone should be able to see a simple version of the menu in action.
IE5.01 Jumping Menu Bug
Anyone using IE5.01 on Windows will notice that the menu jumps around when you hover over some of its items. The problem is easily fixed by modifying our previous hacks as follows:
/* Fix IE. Hide from IE Mac \*/
* html ul li { float: left; height: 1%; }
* html ul li a { height: 1%; }
/* End */
Mystery IE6 Bug:
During the development of this article, I uncovered a strange bug that I believe is only apparent in IE6. A background must be declared on the li a, else when a sub-menu stretches further (vertically) than the main menu itself, the links start to disappear before you have time to click them. Strange! Try it to see for yourself.