The Boxer Menu:
standards-compliant and accessible dropdown menu

This page explains the inner workings of the Boxer Menu (check out the working example!):

  1. The Introduction
  2. The Images
  3. The HTML
  4. The JavaScript
  5. The CSS

The Introduction

Not so long ago, menus on the web were built using DHTML, a combination of HTML, CSS, JavaScript and the DOM. This method often resulted in chunky code, incompatibility across browsers, depressed web developers and inaccessible navigation for disabled users. It was clear that something had to change, not in the least for the disabled users.

A first leap was taken by Douglas Bowman in his ALA articles Sliding Doors of CSS and Sliding Doors of CSS, Part II of October 2003. He used nothing but semantic markup and CSS for building rollover menu tabs. No truckload of JavaScript was hiding in the back, nor had images to be preloaded for a smooth rollover effect. The method was clean, slick, light and swiftly adopted across the Internet. Naturally, his articles are worth a read.

A second landmark was the creation of the Suckerfish menu by Patrick Griffiths and Dan Webb, whose article on the subject was published at ALA in November 2003 as Suckerfish Dropdowns. They had developed a mechanism to create dropdowns using HTML, CSS and only a small amount of JavaScript, thus achieving the dream of a lightweight, accessible, standards-compliant, cross-browser-compatible method.1

At first I simply wanted to make my own menu based on the Suckerfish Dropdown method. A colleague pointed out the Sliding Doors technique and I started wondering whether it was possible to create a standards-compliant and accessible menu based on the two mechanisms.
A first version was finished and used late 2005, but I reconstructed it taking into account compatibility with Safari. The new version was christened Boxer Menu. It should go without saying that I am heavily indebted to Douglas Bowman, Patrick Griffiths and Dan Webb, as you can see for yourself in the following.

A working sample is available. The files discussed have been collected in a downloadable archive for your convenience.

Note: The Boxer Menu is no longer maintained.

The Images

For the design of the images I used the Plastic Tabs tutorial with some small changes. More information on why the buttons are split in two is available from Douglas Bowman's article.

Example of tab background (left) Example of tab background (right)

The only other images are arrows for the daddy list items:

Example of right arrow (normal state) Example of right arrow (over state) Exampe of left arrow (normal state) Example of left arrow (over state)

The HTML

The general outline of the HTML consists of lists, with two additional classes. The daddy class contains another list and thus another dropdown. In the CSS, it will receive a special layout. The second class, left, is used in case the menu becomes too wide. All the dropdowns normally face right, which could become a problem at the far right side of the menu with the dropdown disappearing from the screen. Dropdowns in the left class will face left to prevent this.

The JavaScript

The Boxer Menu uses CSS to trigger the dynamic effects such as the dropdown. This is true for all browsers, except for the Internet Explorer family, that still needs a separate JavaScript to create CSS classes dynamically. The JavaScript was written by Patrick Griffiths and Dan Webb and can be found at htmldog.com.

sfHover = function() {
var sfEls = document.getElementById("tiles").getElementsByTagName("LI");

for (var i=0; i<sfEls.length; i++) {
	sfEls[i].onmouseover=function() {
		this.className+=" sfhover";
	}
	sfEls[i].onmouseout=function() {
	this.className=this.className.replace(new RegExp(" sfhover\\b"),"");
	}
}
}
if (window.attachEvent) window.attachEvent("onload", sfHover);

The CSS

We start off with some basic formatting. The percentage of the font-size is based on Owen Briggs' work at the noodle incident.

body {
  font-size: 76%; 
  font-family: arial, helvetica, serif;
  text-align: left;
  padding: 0em;
  margin: 0em;
  }
  #wrapper {
  padding: 0;
  margin: 0;
  width: 100%;
}
#menu {
  font-size: 1.0em;
}
				

The next step is the construction of the top part containing the menu buttons. This is based on Sliding Doors of CSS and Sliding Doors of CSS, Part II by Douglas Bowman.
None of the lists in the menu should show any list-style. The real work starts with the styling of the list items.
Float: left makes the list items appear next to each other. The left part of our menu image is set as the background of these elements. Since we don't want the anchors to slide over them, we assign a padding-left of 9 pixels, which is the exact width of the image. The width of the li element is set to 6.7em, but this can be altered to your liking. In order to render the width correctly in IE 5.x, I use the simplified box model hack in the last line and throughout the style sheet.

#tiles, #tiles ol {
	list-style: none;
	padding: 0;
	margin: 0;
	}
#tiles li {
	float: left;
	padding-left: 9px;
	background: #fff url("../images/left_both.gif") no-repeat left top;
	width: 6.3em;
	w\idth: 6.7em;
	}
				

The anchors should not be underlined, so we set the text-decoration to none. The right part of the menu button becomes the background of the anchor, which is positioned correctly in the li element by means of padding. The top part of the menu is finished now, except for the dynamic effects.
The changing background is not driven by any JavaScript events, but by the CSS :hover pseudo-class. If the pointer hovers over the list item, the background moves down 148 pixels to show the over state. This works in most browsers, except IE, which still needs some JavaScript to create the sfhover class (cf. supra).

#tiles a {
	display: block;
	color: #333;
	text-decoration: none;
	background: #fff url("../images/right_both.gif") no-repeat right top;
	padding: 0.4em 1em 0.4em 0.4em;
	paddin\g: 0.4em 0 0.4em 0;
}
#menu li:hover, #menu li.sfhover{
		background-position: 0% -148px;
		}
#menu li:hover a, #menu li.sfhover a {
		background-position: 100% -148px;
		color: #fff;
		}

If you wonder what the menu looks like at this stage, you can take a look at the example. The top row of the menu appears as it should, but its layout is inherited by all the other list items. We will deal with that by addressing the underlying list items and declaring their styles as we create the dropdown. The following is mostly based on the Suckerfish menu by Patrick Griffiths and Dan Webb.
The first step is forcing the lists off the screen. This is achieved by a combination of absolute positioning and a left offset of -999em. We also define some straightforward formatting, such as color, border and background. These lists will contain more information, so we make them a bit wider.

#tiles li ol {
	position: absolute;
	left: -999em;
	width: 16.5em;
	w\idth: 17.5em;
	color: #000;
	background: #F1F1F1;
	border: 1px solid #999;
	}
				

The dropdown list of the menu contains two peculiar classes. The first one, daddy, is used to indicate that the list item contains another list. An arrow is placed in the right part of the li. The second class, left, is used in case the menu is too wide. If the dropdown is oriented to the right, it might go off-screen at the far right of the menu. In order to prevent this, we let it face left and the arrow in the daddy class should do so, too.
The other styles are rather straightforward. The li elements in the dropdown are made wider to make them fit in the ordered list. Together with the anchor, their backgrounds are made transparent to make the menu button disappear from the background.

#tiles li.daddy {
	background: url("../images/rightarrow.gif") 90% 50% no-repeat;
	}
#tiles ol.left li.daddy {
	 background: url("../images/leftarrow.gif") 5% 50% no-repeat;
	 padding-left: 2em;
	 }
#tiles li ol li {
	width: 18.3em;
	w\idth: 16.75em;
	background: transparent;
	}
#tiles li ol.left li {
	width: 16.3em;
	w\idth: 15.5em;
	padding-left: 2em;
	}
#tiles li ol li a{
	background: transparent;
}

The third level lists of the menu need some extra positioning. If we let them render automatically, they will simply appear on top of the dropdowns. This can be avoided by forcing them to the left or the right.

#tiles li ol ol {
	margin: -2em 0 0 17.5em;
	mar\gin: -2.1em 0 0 16.7em;
	border: 1px solid #999;
}
#tiles li ol.left ol {
	margin-left: -16.5em;
	mar\gin-left: -17.8em;

}

The only thing our menu lacks now is an engine. Again, we use the :hover pseudo-class for standard-compliant browsers and the sfhover class, generated in the JavaScript, for IE. The second and the third level of the menu should not appear when the user hovers over the menu button, so we let them remain at -999em left of the screen. When the user hovers over a list item, the left positioning should change from -999em to auto. The left class has to face left, so we give it a negative margin-left.

#tiles li:hover ol ol, #tiles li:hover ol ol ol, #tiles li.sfhover ol ol, 
#tiles li.sfhover ol ol ol {
	left: -999em;
}
#tiles li:hover ol, #tiles li li:hover ol, #tiles li li li:hover ol, 
#tiles li.sfhover ol, #tiles li li.sfhover ol, #tiles li li li.sfhover ol {
	left: auto;
}
#tiles li:hover ol a, #tiles li li:hover ol a, #tiles li li li:hover ol a, 
#tiles li.sfhover ol a, #tiles li li.sfhover ol a,
#tiles li li li.sfhover ol a {
	color: #000;
}
#tiles li:hover ol.left, #tiles li.sfhover ol.left {
	margin-left: -7.7em;
	mar\gin-left: -11.2em;
}

If the user hovers over a list item, the background color should change to highlight it. The easiest way of achieving this is by means of a child selector (>) in order to prevent any other descendants from inheriting the background color. Internet Explorer, however, does not understand the child selector, which means that first we have to set the :hover features of the list elements in the first dropdown, then overrule these features for the list elements in the second dropdown, and finally set the :hover features of the second dropdown. Isn't that fun?

#menu #tiles li ol li:hover, #menu #tiles li ol li.sfhover {
	background: #06c;	
}
#menu #tiles li ol li:hover a, #menu #tiles li ol li.sfhover a {
	color: #fff;	
}
#menu #tiles li ol li:hover ol li, #menu #tiles li ol li.sfhover ol li {
	background: #F1F1F1;	
}
#menu #tiles li ol li:hover ol li a , #menu #tiles li ol li.sfhover ol li a {
	color: #000;
}
#menu #tiles li ol li ol li:hover, #menu #tiles li ol li ol li.sfhover {
	background: #06c;
}
#menu #tiles li ol li ol li:hover a , #menu #tiles li ol li ol li.sfhover a {
	color: #fff;
}

Finally, I want the arrow in the daddy class to change to white if the user hovers over the li. This does not work in Internet Explorer, since we cannot use the :hover pseudo-class there and multiple class selectors do not yield the wanted results.

#menu #tiles li ol li.daddy:hover {
  background: #06c url("../images/rightarrow_over.gif") 90% 50% no-repeat;
	}
#menu #tiles li ol.left li.daddy:hover {
  background: #06c url("../images/leftarrow_over.gif") 5% 50% no-repeat;
	 }

The last line is a hack to correct the behaviour in Safari. This browser apparently doesn't take into account the padding of 9 pixels in the first level of the menu if the dropdown is triggered, causing the dropdown list to appear directly under the list item. Other browsers do take the padding into account, which places the dropdown 9 pixels to the right. By using an ibloom hack all browsers except Safari read a margin-left of -9px. Since this is quite an aggressive hack, you should use it with caution.

 #tiles li ol{margin-left:-9px;#}

Safari shows another problem concerning the left dropdown: it appears too far to the right:
Example of problem in Safari
I haven't found a solution for it (yet).