reptile7's JavaScript blog
Sunday, December 02, 2007
Drop-Down Menus, Act III
Blog Entry #96

HTML Goodies' DHTML/Layers sector contains a "Drop-Down Menu" tutorial that predates slightly and prefigures to an extent the rolling menu script of Script Tips #76-78 we've been analyzing in the last couple of entries. The "Drop-Down Menu" tutorial offers a script whose effect mimics the nested drop-down menus that once appeared (but no longer appear) at Microsoft's home page but are still used extensively at Microsoft's MSDN Library; this script, which in its original form only works with MSIE 4+, can be accessed here and is reproduced in the div below:


<title>Pull-Down Menus</title>

<style type="text/css">

#menu1 { display: none; }
#menu2 { display: none; }
#menu3 { display: none; }

a:link { color: black; text-decoration: none; }
a:hover { color: blue; text-decoration: underline; }



<body bgcolor="white">

<table border="0" align="left">

<td valign="top" width="200">
<span onmouseover=" = 'block';" onmouseout=" = 'block';">
<font size="-1"><b><img src="littlex.gif">&nbsp;Goodies Tutorials</b></font></span><br>
<span id="menu1" onclick=" = 'none';">

<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="/tutors/frame1.html">Frames</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="/tutors/tbl.html">Tables</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="/beyond/dhtml.html">DHTML</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="/tutors/forms.html">Forms</a></font>


<td valign="top" width="200">
<span onmouseover=" = 'block';" onmouseout=" = 'block';">

<font size="-1"><b><img src="littlex.gif">&nbsp;Great Sites</b></font></span><br>

<span id="menu2" onclick=" = 'none';"> 

<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">The Straight Dope</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">Van Halen News Desk</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">Dave TV</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">Hair Club for Men</a></font>


<td valign="top" width="200">
<span onmouseover=" = 'block';" onmouseout=" = 'block';">

<b><img src="littlex.gif">&nbsp;<font size="-1">News Sites</font></b></span><br>

<span id="menu3" onclick=" = 'none';">

<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">CNN</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">ABC News</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">USA Today</a></font><br>
<font size="-1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="littledash.gif">&nbsp;<a href="">CBS Market Watch</a></font>





Although you wouldn't know it from looking at the script's demo page, the script's display is housed in a three-row, three-cell table. (We'll see later that the table 'scaffolding' is unnecessary.) Like the Script Tips #76-78 Script's click layer, each table cell holds
(a) an initially visible heading and
(b) an initially invisible set of links.
Unlike the click layer links, the table cell links do not occupy any space on the page; this is because the table cell links are wrapped in span elements whose CSS display property is set to none:

#menu1 { display: none; }
#menu2 { display: none; }
#menu3 { display: none; }
/* These rules can be more compactly written as:
#menu1, #menu2, #menu3 { display: none; }
CSS selector grouping is discussed here. */

The table cell headings are themselves wrapped in span elements equipped with onmouseover/onmouseout commands that drop down their links, for example:

<span onmouseover=" = 'block';" onmouseout=" = 'block';">
<font size="-1"><b><img src="littlex.gif">&nbsp;Goodies Tutorials</b></font></span>

Moving the mouse cursor over the Goodies Tutorials heading pops out the links in the id="menu1" span element by setting the menu1 CSS display property to block, which, as you might guess, displays the links with a block-level rendering, e.g., newlines (\ns) are inserted before and after the links. Contra the tutorial, the display block value does not serve to negate the menu1 display none value that is set in the script's style element.

The onmouseout attribute is redundant; if we delete it, the link menu won't go away if the mouse cursor is moved away from the menu.

In turn, each link-containing span element is equipped with an onclick command that pulls up its link menu when the user clicks in the span region anywhere but on the links, e.g.:

<span id="menu1" onclick=" = 'none';">

From MSIE-specific to cross-browser

You have probably figured out that it is the script's use of the all collection in the onmouseover/onmouseout/onclick commands that makes it MSIE-specific. We first encountered the all collection in the color creation script of Script Tips #65-67 and correspondingly discussed it in detail in Blog Entry #85. Microsoft's all collection page shows that the all syntax here is not quite standard: the menu# span elements should be referenced with document.all("menu#") and not

Anyway, all that is necessary to make the script work with other (current) browsers is to replace each reference with a document.getElementById("menu#") reference - it's that simple.

The Microsoft menu interface

Joe's menus and the Microsoft menus that inspired them actually have different user interfaces. Both sets of menus preface their headings with small 'plus' (The small plus image) images and their links with small 'minus' (The small minus image) images. However, Microsoft's menus are not displayed/vanished via a mouseevent interface; rather, the Microsoft menus
(a) are dropped down by clicking on the heading The small plus image images, which are 'flipped' to the The small minus image images when the links display; and
(b) are pulled up by clicking on the heading The small minus image images, which toggle back to the The small plus image images when the links vanish.

Below I'll show you how to replace Joe's mouseevent interface with the Microsoft interface if you'd like to do that, but let me get some style stuff out of the way first...

A style sheet for the "Drop-Down Menu" tutorial script

body { background-color: white; }
table { border: 0; }
td { width: 200px; vertical-align: top; }
h4 { display: inline; }
#menu1, #menu2, #menu3 { position: relative; left: 25px; }
a:link { color: black; text-decoration: none; }
a:hover { color: blue; text-decoration: underline; }

The HTML 4 Index of Attributes shows that the bgcolor attribute of the body element, the align attribute of the table element, and the width attribute of the td element are all deprecated.
• My preference is to simply remove the table element's align="left" attribute and not replace it with any style declarations (e.g., float:left;) because the script's table is by default left-justified.
• I find that simply removing the td elements' valign="top" attributes does not affect the script's effect (so the td vertical-align:top; declaration is probably unnecessary).
• The style sheet doesn't have a rule replacing the <font size="-1"> elements, which produce text too small for my tastes.
• We will below mark up the boldened menu headings with h4 elements, whose default block-level rendering is switched to inline by the display:inline; declaration above (technically, this declaration puts the h4 elements in the same CSS line boxes that hold the The small plus image images). If you're uncomfortable with skipping the h1-h3 heading levels, then you can alternatively mark up the headings with strong elements, which are inline by default and are typically rendered with a bold font weight.
• Joe gives each menu link a five-space indent via a series of &nbsp; entity references, whose effect is smoothly reproduced by applying position:relative;left:25px; declarations to the menu# span elements.
• The menu# span elements' initial display:none; properties (vide supra) will be written in a script element (vide infra).

Click it

We're now ready to supplant Joe's mouseevent menu interface with the Microsoft click interface described earlier. We begin by recoding the first table cell as:

<img id="image1" src="littlex.gif" onclick="displayx(1);" /> <h4>Goodies Tutorials</h4>
<span id="menu1">
<img src="littledash.gif" /> <a href="">Frames</a><br />
<img src="littledash.gif" /> <a href="">Tables</a><br />
<img src="littledash.gif" /> <a href="">DHTML</a><br />
<img src="littledash.gif" /> <a href="">Forms</a>

The script's original href values for the Frames, Tables, DHTML, and Forms links are not current but are functional; the code above updates them. Joe's littlex.gif (The small plus image) and littledash.gif (The small minus image) images can be accessed at and, respectively. Lastly, there's no need to prevent line-wrapping before the menu heading, so I've replaced the &nbsp; reference between the littlex.gif image and the heading with an ordinary space.

The second and third table cells can be recoded analogously. Next, place the following script element after the third td element:

<script type="text/javascript">

document.getElementById("menu1").style.display = "none";
document.getElementById("menu2").style.display = "none";
document.getElementById("menu3").style.display = "none";

function displayx(num) {
if (document.getElementById("menu" + num).style.display == "none") {
document.getElementById("menu" + num).style.display = "block";
document.getElementById("image" + num).src = "littledash.gif"; }
else {
document.getElementById("menu" + num).style.display = "none";
document.getElementById("image" + num).src = "littlex.gif"; }

A single displayx( ) function handles all three menus. In changing the menu# displays from none to block, I find that the original menu1, menu2, menu3 { display:none; } style rule is not recognized by the script element; the displayx( ) if condition returns false on the first click because its document.getElementById("menu"+num).style.display expression evaluates in this case to an empty string (the expression is subsequently set to none by the else block, after which the script works normally). At least on my computer, the if condition only returns true on the first click if the menu# displays are set to none in the script element.

And that'll do it - try it out in the div below:

The small plus image

Goodies Tutorials

The small minus image Frames
The small minus image Tables
The small minus image DHTML
The small minus image Forms
The small plus image

Great Sites

The small minus image The Straight Dope
The small minus image Project Gutenberg
The small minus image HowStuffWorks
The small minus image
The small plus image

News Sites

The small minus image CNN
The small minus image New York Times
The small minus image BBC
The small minus image Agence France-Presse

(Regarding the Great Sites menu, you'll get no argument from me that Cecil Adams' The Straight Dope is indeed a great Web site, but as for the Van Halen News Desk, Dave TV, and Hair Club for Men, well, I thought other link choices might be more appropriate. I have also restocked the News Sites menu with some different links - why not?)

In looking at the indented links, perhaps you are thinking, "Can't we use list elements to code these menus?" Indeed we can, and we'll restructure the script with a nested list 'chassis' in the next post.


Well said.
Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)