(except in IE 5+ on windows where I use the proprietary DHTML behaviours, because its CSS handling is not good enough to work this menu without script)
This works in Mozilla 1+, Netscape 7+, Opera 7+, Safari build 60+, OmniWeb 4.5+ and IE 5+ on Windows (using DHTML behaviours)
This produces a styled nested list in IE 4, Netscape 4, OmniWeb 4.2-, iCab and WebTV
This does not function as a menu or a complete list in Netscape 6, Opera 6-, Konqueror 3.0-, Konqueror 3.1+ (bug?), Internet Explorer on Mac, ICEbrowser, Escape and Clue browser
[Note, the menu to the right plays on the beautiful design by Brother Cake]
This requires browsers to be able to understand the > selector, to support :hover over li elements, to be able to correctly position li elements relatively, and ul elements absolutely, to support the display style, and to be able to change display when :hover is detected. Alternatively, a conditional comment and DHTML behaviours make it work in IE 5+. See below for all the CSS used to make it work - substantially smaller than the equivalent JavaScript.
Glad you asked. As I have already said, it is substantially smaller than the equivalent JavaScript. It does not need ANY JavaScript knowledge to set it up. Browsers that do not understand it will simply show a nested list so that the menu could still be used - with JavaScript menus, these browsers would show nothing. With many browsers, the menu will work, even if the user has disabled JavaScript. You can make any nested list into a menu simply by making its class 'makeMenu'.
To position this menu elsewhere on the page, all you need to do is make ul.makeMenu positioned using CSS positioning, and changing the colours is easy using the stylesheets and the HTC file. To make the menu open to the left instead of to the right, just change the 78px to -78px (both times).
I knew you would want to know that. Because the menu relies on :hover and changing the display style on :hover, it will not work in all the major browsers. Even though I can make lesser browsers ignore it, there are a few browsers that understand enough CSS to make a mess, but not enough to operate the menu. If you wanted to check for these browsers, you could not do so using CSS alone and you would require some form of client sniffing using JavaScript or server side sniffing. Also, because :hover is used and not events, it is not possible to make the menus stay open for a couple of moments when the mouse moves off them - useful if you accidently move your mouse too far etc. In browsers where this menu works, it is impossible to use the menu without a mouse - a few well designed JavaScript menus do allow the menus to be operated using the keyboard alone.
| Browser | > selector | :hover over li | positioning li and ul | display | changing display with :hover | DHTML behaviours | result |
|---|---|---|---|---|---|---|---|
| Mozilla 1 | Y | Y | Y | Y | Y | N | Works correctly |
| Netscape 7 | Y | Y | Y | Y | Y | N | Works correctly |
| Opera 7 | Y | Y | Y | Y | Y | N | Works correctly |
| Netscape 6 | Y | N | Y | Y | Y | N | Only the top level is visible |
| Opera 6 | Y | N | Y | Y | N | N | Only the top level is visible |
| Internet Explorer 5+ | N | N | Y (not early 5.0) | Y | Y | Y | Works correctly (not early 5.0) |
| Internet Explorer 4 | N | N | Y | Y | Y | N | Styled list |
| IE Mac | Y | N | Y | Y | N | N | Only the top level is visible |
| Konqueror 3.1+ | Y | Y | Y | Y | Y | N | Should work correctly but does not appear to (browser bug?) |
| Konqueror 3.0- | Y | Y | Y | Y | N | N | Only the top level is visible |
| Safari / OmniWeb | Y | Y | Y | Y | Build 60+ | N | Works correctly (build 60+ - otherwise only the top level is visible) |
| ICEbrowser | Y | Y | N | Y | N | N | Only the top level is visible |
| Escape | Y | N | N | Y | N | N | Only the top level is visible |
| Clue browser | Y | BUG | N | Y | N | N | Only the top level is visible |
| Netscape 4 | N | N | N | Y | N | N | Styled list |
| Omniweb | N | N | N | Y | N | N | Styled list |
| iCab | N | N | N | Y | N | N | Styled list |
| WebTV | N | N | N | N | N | N | Styled list |
| Non CSS browsers | N | N | N | N | N | N | Unstyled list |
<ul class="makeMenu"> <li>>> Lips <ul> <li><a href="cat.html">Cat</a> <li><a href="rabbit.html">Rabbit</a> <li><a href="dingo.html">Dingo</a> </ul> <li>>> Ears <ul> <li>Elephant >> <ul> <li><a href="indian.html">Indian</a> <li><a href="african.html">African</a> </ul> <li><a href="monkey.html">Monkey</a> <li><a href="dog.html">Dog</a> </ul> <li>>> Eyes <ul> <li><a href="pig.html">Pig</a> <li><a href="bird.html">Bird</a> <li><a href="worm.html">Worm</a> </ul> <li>>> Noses <ul> <li><a href="bat.html">Bat</a> <li><a href="fish.html">Fish</a> <li><a href="panther.html">Panther</a> </ul> </ul>
For practical uses, you would remove the comments
NOTE: it is vital that the ULs are given a background colour, or Internet Explorer does not recognise mouseovers / mouseouts correctly.
<style type="text/css"><!--
ul.makeMenu, ul.makeMenu ul {
width: 80px; /* sets the size of the menu blocks */
border: 1px solid #000; /* puts a black border around the menu blocks */
background-color: #8aa; /* makes the menu blocks mint green - a bg-color MUST be included for IE to work properly! */
padding-left: 0px; /* stops the usual indent from ul */
cursor: default; /* gives an arrow cursor */
margin-left: 0px; /* Opera 7 final's margin and margin-box model cause problems */
}
ul.makeMenu li {
list-style-type: none; /* removes the bullet points */
margin: 0px; /* Opera 7 puts large spacings between li elements */
position: relative; /* makes the menu blocks be positioned relative to their parent menu item
the lack of offset makes these appear normal, but it will make a difference
to the absolutely positioned child blocks */
color: #fff; /* sets the default font colour to white */
}
ul.makeMenu li > ul { /* using the > selector prevents many lesser browsers (and IE - see below) hiding child ULs */
display: none; /* hides child menu blocks - one of the most important declarations */
position: absolute; /* make child blocks hover without leaving space for them */
top: 2px; /* position slightly lower than the parent menu item */
left: 78px; /* this must not be more than the width of the parent block, or the mouse will
have to move off the element to move between blocks, and the menu will close */
}
ul.makeMenu li:hover, ul.makeMenu li.CSStoHighlight {
background-color: #ffa; /* gives the active menu items a yellow background */
color: #000; /* makes the active menu item text black */
}
ul.makeMenu ul.CSStoShow { /* must not be combined with the next rule or IE gets confused */
display: block; /* specially to go with the className changes in the behaviour file */
}
ul.makeMenu li:hover > ul { /* one of the most important declarations - the browser must detect hovering over arbitrary elements
the > targets only the child ul, not any child uls of that child ul */
display: block; /* makes the child block visible - one of the most important declarations */
}
/* and some link styles */
ul.makeMenu li a { color: #fff; display: block; width: 100%; text-decoration: underline; }
ul.makeMenu li a:hover, ul.makeMenu li a.CSStoHighLink { color: #000; }
ul.makeMenu li:hover > a { color: #000; } /* supports links in branch headings - must not be display: block; */
--></style>
<!--[if gte IE 5]>
<style type="text/css">
/* that IE 5+ conditional comment makes this only visible in IE 5+ */
ul.makeMenu li { /* the behaviour to mimic the li:hover rules in IE 5+ */
behavior: url( IEmen.htc );
}
ul.makeMenu ul { /* copy of above declaration without the > selector */
display: none; position: absolute; top: 2px; left: 78px;
}
</style>
<![endif]-->
<attach event="onmouseover" handler="rollOver" />
<attach event="onmouseout" handler="rollOff" />
<script type="text/javascript">
function rollOver() {
//change the colour
element.className += (element.className?' ':'') + 'CSStoHighlight';
//change display of child
for( var x = 0; element.childNodes[x]; x++ ){
if( element.childNodes[x].tagName == 'UL' ) { element.childNodes[x].className += (element.childNodes[x].className?' ':'') + 'CSStoShow'; }
if( element.childNodes[x].tagName == 'A' ) { element.childNodes[x].className += (element.childNodes[x].className?' ':'') + 'CSStoHighLink'; }
}
}
function rollOff() {
//change the colour
element.className = element.className.replace(/ ?CSStoHighlight$/,'');
//change display of child
for( var x = 0; element.childNodes[x]; x++ ){
if( element.childNodes[x].tagName == 'UL' ) { element.childNodes[x].className = element.childNodes[x].className.replace(/ ?CSStoShow$/,''); }
if( element.childNodes[x].tagName == 'A' ) { element.childNodes[x].className = element.childNodes[x].className.replace(/ ?CSStoHighLink$/,''); }
}
}
</script>
This menu was inspired by (and the basic technique taken from) Eric Meyer's Pure CSS Menus. The idea of using DHTML behaviours and conditional comments was inspired by Brother Cake's CSS / DHTML Hybrid Navigation Bar. Brother Cake's page also shows another way to do this. Instead of using DHTML behaviours, he uses regular JavaScript. Although this does make the scripting significantly more complex, this still retains the advantages of CSS menus, but also extends support to Konqueror, Internet Explorer on Mac and ICEbrowser, as long as JavaScript is enabled. I fully support this idea, but I have not yet written my own version of the required script.