Scripting Drop-Down Menu Behavior
You now have a list of links that looks like a drop-down menu. All you need now is a script to make it act like one. Your script will set up the menu when the page loads, and respond to event handlers to show and hide the submenus.
Setting Up the Menu
The SetupMenu() function will run when the page loads, and then configure the drop-down menu. This mainly consists of hiding the submenus and configuring some event handlers. The function will use a loop to look at all of the <li> elements in the page, and if they have a class attribute of menu, they're considered part of the menu. The following lines set up the event handlers for the link and hide the submenu:
thelink=findChild(items[i],"A");
thelink.onmouseover=ShowMenu;
thelink.onmouseout=StartTimer;
//is there a submenu?
if (ul=findChild(items[i],"UL")) {
ul.style.display="none";
The findChild() function is used twice here. This function will also be defined in your script, and will return the first child item of a particular type it finds for an object. In the preceding lines, it is used to find the link (<a> tag) under the list item, and to find the nested list of subitems (<ul> tag). The style.display property is used to hide each submenu.
Showing a Submenu
The ShowMenu() function will be called by the onmouseover event handler when you move over a link. Here's an excerpt from this function that handles showing the submenu:
// find the submenu, if any
ul = findChild(thislink,"UL");
if (!ul) return;
ul.style.display="block";
Once again, findChild() is used to find the <ul> element under the current item, and the display property is set to block to display the menu.
Hiding Submenus
The logic for showing the submenus is simplewhenever the mouse pointer is over a menu heading, the corresponding submenu is displayed. Hiding a submenu is a bit more complicatedthe menu needs to stay open while you select an item, but get out of the way quickly when you're not using it. The HideMenu() function will accomplish this:
function HideMenu(thelink) {
// find the submenu, if any
ul = findChild(thelink,"UL");
if (!ul) return;
ul.style.display="none";
}
One time you definitely want a menu to be hidden is when the user opens another menu, so the ShowMenu() function will call HideMenu() to hide the previous menu. You also want the menu to disappear if you move out of it, but a simple onmouseout event handler won't work because the user could have moved off the menu heading and into the submenu. Instead, the onmouseout event calls the StartTimer() function:
function StartTimer() {
t = window.setTimeout("HideMenu(current)",200);
}
This function sets a timeout to hide the menu in 200 milliseconds. If the user moves over any of the submenu items during the delay, the timer is reset with the ResetTimer() function:
function ResetTimer() {
if (t) window.clearTimeout(t);
}
This function cancels the timeout using the clearTimeout() method, keeping the menu on the screen until the onmouseout event starts the timer again. Finally, some additional lines in the SetupMenu() function will set up event handlers to call StartTimer() and ResetTimer() for each subitem:
for (j=0; j<ul.childNodes.length; j++) {
ul.childNodes[j].onmouseover=ResetTimer;
ul.childNodes[j].onmouseout=StartTimer;
}
Completing the Script
You can now combine all of the functions discussed above to create working drop-down menus. The complete drop-down menu script is shown in Listing 21.3.
Listing 21.3. The Complete JavaScript File for the Drop-Down Menus
// global variables for timeout and for current menu
var t=false,current;
function SetupMenu() {
if (!document.getElementsByTagName) return;
items=document.getElementsByTagName("li");
for (i=0; i<items.length; i++) {
if (items[i].className != "menu") continue;
//set up event handlers
thelink=findChild(items[i],"A");
thelink.onmouseover=ShowMenu;
thelink.onmouseout=StartTimer;
//is there a submenu?
if (ul=findChild(items[i],"UL")) {
ul.style.display="none";
for (j=0; j<ul.childNodes.length; j++) {
ul.childNodes[j].onmouseover=ResetTimer;
ul.childNodes[j].onmouseout=StartTimer;
}
}
}
}
// find the first child object of a particular type
function findChild(obj,tag) {
cn = obj.childNodes;
for (k=0; k<cn.length; k++) {
if (cn[k].nodeName==tag) return cn[k];
}
return false;
}
function ShowMenu(e) {
if (!e) var e = window.event;
// which link was the mouse over?
thislink = (e.target) ? e.target: e.srcElement;
ResetTimer();
// hide the previous menu, if any
if (current) HideMenu(current);
// we want the LI, not the link
/ thislink = thislink.parentNode;
current=thislink;
// find the submenu, if any
ul = findChild(thislink,"UL");
if (!ul) return;
ul.style.display="block";
}
function HideMenu(thelink) {
// find the submenu, if any
ul = findChild(thelink,"UL");
if (!ul) return;
ul.style.display="none";
}
function ResetTimer() {
if (t) window.clearTimeout(t);
}
function StartTimer() {
t = window.setTimeout("HideMenu(current)",200);
}
// Set up the menu when the page loads
window.onload=SetupMenu;
|
Here's a summary of how the script works from top to bottom:
The first line defines two global variables: t stores a reference to the timeout so that it can be canceled, and current is the object for the currently open menu. The SetupMenu() function sets up event handlers to call ShowMenu(), StartTimer(), and ResetTimer(), and hides the submenus. The findChild() function is used by several of the other functions to find a child object. The ShowMenu() function shows a menu. The HideMenu() function hides a menu when the timeout expires. The StartTimer() and ResetTimer() functions manage the timeout discussed earlier. The final line of the script sets the window's onload event handler to the SetupMenu() function to set up the menu when the page loads.
To try the menu, first be sure you have all three files in the same folder: the HTML document, the CSS file (dropdown.css), and the JavaScript file (dropdown.js). You can then load the HTML document into a browser. Figure 21.5 shows the drop-down menu in action.
|
Although the menu works as it is, the CSS could use some improvement. The menus are not well delineated, and there are no rollover effects to let you know you're moving over menu items. Also, to make a menu appear, you have to move the mouse over the text of the menu namefor this menu to work like users expect, the entire block that contains the menu name should be active.
An improved CSS style sheet can solve these problems. You might also want to add more CSS rules to fine-tune its formatting. Here are some suggestions:
Change the fonts and colors to match your site. Add an a:hover selector to make the subitems change color as you move over them. Use border attributes to add borders around menus or subitems. Use margin attributes to add space between menu items.
Listing 21.4 shows a modified style sheet that makes the menu work as it should, and implements several of these ideas to create a menu with a different style.
Listing 21.4. A Style Sheet for a Different Style of Menu
/* The whole menu */
#menu {
position: absolute;
font-family: sans-serif;
font-size: 100%;
}
/* Each menu name */
#menu li {
float: left;
list-style-type: none;
width: 102px;
background-color: silver;
border: 1px solid black;
text-indent: 0px;
margin-left: 3px;
}
/* each main menu link */
#menu li a {
color: black;
text-decoration: none;
width: 100%;
display: block;
}
#menu li a:hover {
color: white;
}
/* The entire submenu */
#menu li ul {
background-color: silver;
margin: 0px;
padding: 0px;
}
/* Each submenu item */
#menu li ul li {
padding: 0px;
margin: 0px;
float: none;
list-style-type: none;
width: 100px;
text-indent: 0px;
border: none;
}
#menu li ul li a{
color: black;
text-decoration: none;
}
#menu li ul li a:hover{
color: black;
background-color: aqua;
}
|
This style sheet has the following features:
A sans-serif font is used for a more modern appearance. Borders and margins are used to make the menu names appear as separate boxes. An a:hover selector is used to make the menu names change color when the mouse is over them. The width: 100% and display: block rules for the menu names make the entire box active, not just the text. Another a:hover selector makes the submenu items change color when the mouse is over them. The width: 100% rule for submenu items makes the entire width of the submenu active, not just the text.
To use this style sheet, save it as dropdown2.css in the same folder as the HTML document, and change the <link> tag in the HTML document to refer to the new file. Figure 21.6 shows the drop-down menu with this style sheet.
By the Way
See Hour 12, "Working with Style Sheets," for more information about using CSS styles to format HTML elements.
|
|
Main Menu
|