Accessible, Valid Dropdown Menu or Popup Menu using CSS and Semantic HTML
We’ve all seen dropdown / popup menu lists on websites before, and generally they’re extremely useful because they save space, but offer extra functionality. Sometimes, though they’re tricky to implement. I remember doing a image-only popout menu for the Lonsdale Views, who offer accommodation in Point Lonsdale and it was more difficult than expected - First, there was Internet Explorer’s lack of support for “:hover” and then there was Internet Explorer’s z-index issue. Now that I’ve got a blog, I thought I’d publish a how-to guide for valid, accessible semantic HTML and CSS dropdown menus… But before we get started, here’s a basic demo of the HTML and CSS dropdown list.
The HTML
After some searching around, the most appealing solution I found was the Suckerfish solution. Using the Suckerfish solution, a dropdown menu can be marked up using semantic HTML - more specifically - lists. Here’s an example:
<ul id="nav"> <li><a href="#">Menu 1</a> <ul> <li><a href="#">Submenu 1</a></li> <li><a href="#">Submenu 2</a></li> <li><a href="#">Submenu 3</a></li> </ul> </li> <li><a href="#">Menu 2</a> <ul> <li><a href="#">Submenu 1</a></li> <li><a href="#">Submenu 2</a></li> <li><a href="#">Submenu 3</a></li> </ul> </li> <li><a href="#">Menu 3</a></li> </ul>
CSS Part 1
As you can see, this is some very clean HTML or XHTML code which is great for search engines, accessibility and validation - not to mention code maintenance. Now, we just need to apply some CSS styles to the elements to turn this list into a dropdown menu or popup menu.
Using the Suckerfish solution, these are the styles to add:
#nav, #nav ul {
padding: 0;
margin: 0;
list-style: none;
}
#nav a {
display: block;
width: 10em;
}
#nav li {
float: left;
width: 10em;
}
CSS Part 2
That CSS gets the root menu’s visual structure up, now we need to organise the actual dropdown menus. We need to hide the drop down lists until the user hovers over the root of that particular drop down list. To do this, it seems the most accessible multi-platform solution is to move it out of sight using “left:-999em” rather than “display:none” which is known to be inaccessible. On the hover event, we move it back beneath the root using “left:auto” because “left:0″ causes a problem in Opera.
Here’s the CSS for showing and hiding the dropdown lists:
#nav li ul {
position: absolute;
width: 10em;
left: -999em;
}
#nav li:hover ul {
left: auto;
}
The Special :hover Case of Internet Explorer
Done, you now have a perfectly functioning, semantic, valid, accessible menu - right? Not quite - this still doesn’t work in Internet Explorer because it doesn’t happen to have full support for the “:hover” pseudo class but that’s Ok. Because those geniuses at HTMLDog created Suckerfish - a very small Javascript script that will solve this problem in no time, add this to your head section:
sfHover = function() {
var sfEls = document.getElementById("nav").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);
What Suckerfish does is goes through all LI elements in #nav and adds the class “sfHover” onMouseOver (when the user hovers over the list item) and removes the class onMouseOut. Or in other words, it solves our problem.
There’s only one thing left to do, and that’s change a bit of the CSS that shows the dropdown menus to include the new “sfHover”:
Change:
#nav li:hover ul {
left: auto;
}
To:
#nav li:hover ul, #nav li.sfhover ul {
left: auto;
}
And that’s it! Here’s a working demo of the valid, accessible HTML and CSS drop down menu.
Solution for Overlapping Elements or Hidden Menu
Sometimes, there’s STILL more trouble. When implementing this menu for Lonsdale Views, I came across a problem - the menus were being obstructed or hidden behind other elements! So I went ahead and used z-index to let the browser know that the menu needed to be on top. Huzzah, it works! Oh, not in Internet Explorer - what a surprise. I spent quite some time searching the internet for a solution…
Eventually I read that Internet Explorer passes z-index from parent to child, so even if you give a “4th generation” element a z-index of 1000, the z-index can’t be greater than the lowest z-order of any parent elements!
The solution to your menus being obstructed or hidden behind images, hidden behind pictures, hidden behind text, hidden behind flash, hidden behind everything:
Give each parent element of the #nav element isn’t common with the obstructing element a HIGH z-index (let’s say, 100) and give the element containing the elements obstructing your menu a LOWER z-index (let’s say 0)
For example, if this was part of your page:
<div id="container"> <div id="topbar"> <ul id="nav"> ... the menu code is here ... </ul> </div> <div id="content"> ... the element(s) that obstruct or are hiding your menu ... </div> </div>
You could use this CSS to remedy your problems:
#topbar, #nav {
z-index:100;
}
#content {
z-index:0;
}
Hope this has saved you some time and taught you something. If you really appreciate it, leave a comment and even go and say thanks to the crew at HTMLDog - this is all because of them!
Flash Objects Obstructing or Overlapping Menu
Sometimes, even when all of the CSS is correct, your menus might be overlapped by flash objects. For example, when you hover over, your CSS menu is hidden behind a flash object. The solution to this is actually somewhat simple and cross-browser. All that you need to do is add the transparency parameter to your embed / object code, like so:
<object type="application/x-shockwave-flash" width="100" height="100"> <param name="wmode" value="transparent" /> <param name="movie" value="flash.swf" /> <embed wmode="transparent" src="flash.swf" width="100" height="100" /> </object>
Notice how “<param name=”wmode” value=”transparent” /> has been added? Also, don’t forget to add the ‘wmode=”transparent’” to the EMBED tag - that is imporant for non-Internet Explorer browsers. Now obviously, you need to change the “src” attributes and the movie value to whatever the URI of your flash file is.
Happy coding!
Tags: advice, css, firefox, flash, html, internet-explorer, javascript, navigation, problems, semantic, solutions, Tips




PlugIM.com
Accessible%2C Valid Dropdown Menu or Popup Menu using CSS and Semantic HTML…
We’ve all seen dropdown / popup menu lists on websites before, and generally they’re extremely useful because they save space, but offer extra functionality. Sometimes, though they’re tricky to implement - especially valid ones that are accessibl…
December 28, 2007 @ 10:49 pm
Petr Kabát
You´ve got a mistake in javascript. In regexp must be \\b not only \b.
January 5, 2008 @ 12:10 am
Tim
@Petr Kabát:
Thanks, I edited it. I assume Wordpress butchered it (as it sometimes does).
January 5, 2008 @ 12:18 am
Unhappy with IE
This “solution” failed as expected
January 29, 2008 @ 5:00 pm
Esté Visser
Thanks for the help! Got my swf object to go behind my ccs dropdown in Explorer! I hate IE!!! ;0)
March 10, 2008 @ 7:59 pm
Melissa
I z-indexed the crap out of my menu. It works! It works! (Even in IE.) You are my hero.
April 30, 2008 @ 8:56 am
Tim
@ Unhappy with IE
*You* failed, as expected.
April 30, 2008 @ 5:35 pm
shadeydave
Hi guys,
I tried this as well, and it didn’t work. Although I love the use of the -999em thing to keep the page accessible. Good stuff.
Anyway… IE7 renders flash with the javascript so don’t forget to put your transparency code in here as well. see below:
AC_FL_RunContent( ‘codebase’,'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0′,’width’,'687′,’height’,'460′,’src’,'gallery’,'quality’,'high’,'plugins page’,'http://www.macromedia.com/go/getflashplayer’,'movie’,'gallery’ ,’wmode’,'transparent’ ); //end AC code
This is completely outside of your flash parameters and embed object tags. So remember code kiddies, you need to reference the wmode 3 times in order to get it to work! Craptastic!
June 25, 2008 @ 11:23 pm
shadeydave
Man wordpress screwed up my code one sec…
“
AC_FL_RunContent( ‘codebase’,'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0′,’width’,'687′,’heigh t’,'460′,’src’,'gallery’,'quality’,'high’,'plugins page’,'http://www.macromedia.com/go/getflashplayer’,'movie’,'gallery’ ,’wmode’,'transparent’ ); //end AC code
“
June 25, 2008 @ 11:24 pm
Tim
Thanks for that shadydave
I’m SURE that will be helpful to some of the visitors.
June 30, 2008 @ 7:37 pm
chris woolard
Thanks for the menu code. It works great. but I haven’t been able to solve the ie hover issue. I tried to use the java code you gave me…I did it inline and I also tried to reference an external .js document.
But I’m not very java savvy. Can you help me please!
July 16, 2008 @ 7:28 am
nick
SPTa7F hi! hice site!
July 29, 2008 @ 2:17 pm
errr
Whichever way you look at it … the suckerfish example, and thus this copy of it, is not accessible. If scripting is disabled, it will not work in IE … which makes it usable in about 20% of browsers and devices which have scripting disabled.
August 18, 2008 @ 11:17 am