visibility drop down menu system
Put your text ad here
WestNIC provides reliable web hosting services
This article demonstrates a DOM1 drop-down menu system using the CSS visibility property. Each menu has a main link and an unordered list of links that become visible, with the illusion of extending the main menu point downwards. The drop down menus are open source, accessible and forward compatible.
The scripts and CSS for these drop down menus is provided under a Creative Commons License.
Developing DHTML that is fully backward- forward- and cross-compatible with all browsers has been a fundamental problem since client-side scripting was implemented in more than one Web browser. The DOM1 recommendation from the W3C defines a standard hierarchy of reference objects for HTML 4.01 and XHTML 1.0 documents that should at least make browser-safe forward-compatible scripting feasible.
This demonstration page is assumed to be safe in all browsing circumstances; it will not cause Javascript errors, but is only intended to be fully supported by DOM1 enabled browsers. The scripting is not intended to work with the mutually incompatible, proprietary DOMs implemented by Netscape 4 and Internet Explorer 4 or earlier browsers; in these cases the browser just displays the main menu points statically. On the other hand, the code is guaranteed to be forward-compatible because it uses method, object and property checking to ensure that only DOM1 enabled browsers execute the relevant code.
These menus also implement tab navigation in supporting browsers by placing tabindex attributes on each link. These are combined with Javascript onfocus and onblur event handlers that control the menus in the same way as the onmouseover and onmouseout events respectively. If you press the tab key on your keyboard, the first menu heading should be selected and the menu list will open. Subsequent tabs will select each item in the menu list, then select and open the second menu and continue to the last. Press enter to open a selected link. Press shift+tab to move backwards through the items.
The main menu builder script includes a couple of workarounds to address slight inconsistencies in the way that Opera 4.0 and Internet Explorer 5.0 handle the CSS z-index property and the DOM1 .style.visibility property respectively. Both workarounds use browser-neutral condition checking to be meticulously fail-safe and don't affect the script's DOM1 compatibility.
This page has been tested and successfully debugged in the following browsers. The scripts are compatible and fully supported by the DOM1 enabled browsers in the Supported column.
| Browser | Compatible | Supported |
|---|---|---|
| Internet Explorer | 3.0, 4.0 | 5.0, 5.5 and all versions since |
| Firefox | 0.8, 0.9.1 and all versions since | |
| Mozilla | M15, 0.9.3, 1.3.1 | |
| Netscape Navigator | 3.04, 4.5, 4.73 | 6.0, 7.1 |
| Opera | 3.62 | 4.0, 5.0 and all versions since |
| Safari | 85, 94 and all versions since |
Netscape version 7.1 is based on Mozilla version 1.4. Firefox is also based on the Mozilla browser.
It has been reported that the standard Code Style stylesheets crash Netscape Navigator 4 on Windows XP and Windows 2000 when viewed with this page. These style sheets have since been hidden from Netscape 4. It has also been reported that the Mac Safari browser does not render this menu system accurately; the menus appear twice, slightly offset (Safari screen shot, 60KB). However, Safari version 85 and 94 are reported to render the menus successfully.
If you encounter a problem with this page using a browser not listed here, please use the article feedback form below to submit a report.
The scripting, CSS and XHTML markup for this drop down menu system is described below and the source code is heavily commented for reference. The scripts and CSS for these drop down menus is provided under a Creative Commons License.
For easy maintenance and modular design, all the Javascript (and CSS) for this page is referenced from external files. Unsupported browsers such as Internet Explorer 3 and Netscape 2 with Javascript on will not display these menus at all, nor any noscript element, so this menu system should not be used for essential navigation links. The external script and CSS files are as follows, see below for details:
As with all Javascript for the Web, one cannot be sure that the end-users' browser has Javascript support, so there is a noscript block with links for each of the main menu points using similar markup to the dynamic menus so that the styles may still be presented accurately even if Javascript is off.
visibility-HorizontalMenus.shtml
The markup fragment below specifies the supplementary stylesheet for this page and the initial script element that loads the menu builder script:
<link rel="stylesheet" type="text/css" href="/styles/javascript/dom/visibility-HorizontalMenus.css" /> <script type="text/javascript" src="/scripts/dom/css/visibility-HorizontalMenuBuilder.js"> </script>
The fragment below shows the script element that loads the menu writer script and inserts the dynamic menus immediately after the open body tag. There is also a simplified noscript alternative with equivalent id attributes:
<script type="text/javascript" src="/scripts/dom/css/visibility-HorizontalMenuWriter.js"> </script> <noscript> <div id="NavBar"> <!-- LinkBar points should match LinkBar points in /scripts/dom/css/visibility-HorizontalMenuBuilder.js --> <div id="LinkBar"> <div id="Link1"><a href="/">Home page</a></div> <div id="Link2"><a href="#">Javascript</a></div> <div id="Link3"><a href="#">DOM</a></div> <div id="Link4"><a href="#">CSS</a></div> <div id="Link5"><a href="#">What's New</a></div> </div> </div> </noscript>
visibility-HorizontalMenuBuilder.js
This menu builder script defines the drop-down menu contents and event handler functions for the menus. If the DOM1 getElementById() method is supported, the string variable menutxt is used to build the menu headings and bullet lists. If this basic DOM1 feature is not supported, a simplified group of menu headings is compiled equivalent to the noscript markup.
if (document.getElementById){ // DOM1 statements }
This script also checks if DOM1 object references and properties are available before use, in particular the elements' .style object and .style.visibility property, see the menuOver() example below.
All core Javascript features are assumed to be available if this external script file is loaded and are not explicitly checked. The script is not listed here because of long lines but is heavily commented for reference, see visibility-HorizontalMenuBuilder.js.
menuOver()
The menuOver() function is called directly when the cursor triggers the onmouseover event on one of the five menu headings. This function checks if any other menus are "open" and, if so, closes them immediately. It then opens, or makes visible, the relevant menu by reference to its visibility property via the global variable LiveMenu.
This function includes a minor workaround to check that the LiveMenu.style.visibility property is not null, as this value initially appears to be the empty string in Internet Explorer 5.0 (in IE4.0 compatibility mode at least) and does not return true.
// This is the new 'live' menu, make it visible LiveMenu = document.getElementById(MenuID); // LiveMenu.style.visibility is // initially empty in IE5 until // it is assigned by these // functions, so must check that // it's not null before proceeding... if ((LiveMenu.style) && (LiveMenu.style.visibility != null)){ LiveMenu.style.visibility = 'visible'; }
After this statement sets the visibility property, IE5 returns true to the simpler conditions in the other event handler functions, which simply check for the existence of the .style.visibility property.
stayOpen()
Even when the extended menus' visibility property is hidden, Opera 4.0 registers onmouseover events on the drop-down bullet lists because it does not support the CSS z-index property. The stayOpen() function is a workaround to suppress this behaviour, which simply checks to see if the menu is logically "open" and forwards a call to menuOver() if it is. If the menu is supposed to be closed, the function returns immediately.
function stayOpen(MenuID){
// If menuOver has not been called
// or the menu is hidden, do nothing
if ((LiveMenu == null)||
((LiveMenu.style) &&
(LiveMenu.style.visibility) &&
(LiveMenu.style.visibility == 'hidden'))) return;
else menuOver(MenuID);
}
menuOut()
The menuOut() function is triggered by onmouseout events in the exposed bullet list anchors. The function initialises a setTimeout() control that holds a given menu open for 250 milliseconds so the user can move the cursor down the list before it closes. If stayOpen() calls are triggered by the onmouseover event handlers in these lists, the menus stay open. If not, the hideNow() function is called when the timeout expires.
hideNow()
As its name implies, this function immediately "closes", or makes hidden, whichever menu is specified by the global LiveMenu variable:
if ((LiveMenu.style) && (LiveMenu.style.visibility)) { LiveMenu.style.visibility = 'hidden'; }
visibility-HorizontalMenuWriter.js
This menu writer script simply writes the XHTML markup for the menus defined in the menu builder script into the flow of the document. If the global string variable menutxt has not been defined for whatever reason, the menus will not be output. The listing for visibility-HorizontalMenuWriter.js is given below:
// If menutxt is defined and not // empty, write it to the document /////////////////////////////////////// if ((menutxt) && (menutxt != '')) { document.write(menutxt); }
Here again, the core Javascript method document.write() is assumed to be available if this external script file has loaded.
visibility-HorizontalMenus.css
This stylesheet, visibility-HorizontalMenus.css, supplements the standard site-wide Code Style CSS to declare styles specifically for these drop-down menus. It uses an @import rule to hide the main styles from Netscape 4 and Internet Explorer 3, but some simple styles are included to improve appearances where supported.
/* Created: 2000-10-21 Issued: 2001-01-11 Modified: 2005-02-23 Copyright (c) 2001-2006 by Philip Shaw, phil@codestyle.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. */ @import url(visibility-HorizontalMenusImport.css); /* Basic styles for NN4. */ #Link1, #Link2, #Link3, #Link4, #Link5 { float: left; width: 17.9%; } #Header{ clear: left; }
The series of grouped #Link1 declarations refer to the main link heading div elements, which float horizontally across the top of the page. These are sized using percentage lengths to ensure that these menu panels will scale proportionally to fit most screen resolutions. These are styled in more detail by margin, padding and border declarations in the @import stylesheet.
visibility-HorizontalMenusImport.css
The @import stylesheet, visibility-HorizontalMenusImport.css, declares the detailed presentation of the menus for supporting browsers. Non-supporting browsers will display a simpler page format. In many cases the declarations have been grouped to ensure that display properties and positioning of the menu and bullet list containers, #LinkBar and #MenuBar, are almost identical. The vital exceptions are the z-index and vertical positioning given by the top property, which makes them overlap very slightly on the bottom edge of the menu heading divs.
/* Created: 2000-11-12 Issued 2001-01-11 Modified: 2010-04-05 Copyright (c) 2001-2009 by Philip Shaw, phil@codestyle.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. */ /* Increase depth of top bar for menus */ #TopBar { padding-top: 2.5em; } #MenuBar, #LinkBar { float: none; width: 95.9%; position: absolute; left: 2.7%; border: none; } /* z-index necessary to make links visible in Netscape 6 */ #MenuBar { top: 1.5em; z-index: 4; } #LinkBar { top: 0.1em; z-index: 3; } /* Main menu and link styles identical. */ #Menu1, #Menu2, #Menu3, #Menu4, #Menu5, #Link1, #Link2, #Link3, #Link4, #Link5 { float: left; width: 17.9%; border-style: solid; border-color: #fefefe #dfdfdf #666 #ccc; margin: 0.6% 0.2%; padding-left: 1%; color: #039; background: #f9f9f9; font-family: "Bitstream Charter", "URW Palladio L", Palatino, "Palatino Linotype", "Hoefler Text", Georgia, "Book Antiqua", Times, "Times New Roman", serif; font-weight: normal; font-size: 1.1em; } /* Differences in menu and link styles. */ #Menu1, #Menu2, #Menu3, #Menu4, #Menu5 { border-width: 0px 2px 1px 2px; visibility: hidden; } #Link1, #Link2, #Link3, #Link4, #Link5 { border-width: 2px 2px 1px 2px; visibility: visible; height: 1.3em; } /* Must override float on the menu divs. */ #Menu1 ul, #Menu2 ul, #Menu3 ul, #Menu4 ul, #Menu5 ul { float: none; margin: 0em 0em 0em 1em; padding: 0.2em 0em 0.5em 0em; font-family: "Bitstream Charter", "URW Palladio L", Palatino, "Palatino Linotype", "Hoefler Text", Georgia, "Book Antiqua", Times, "Times New Roman", serif; } /* Make the whole width of the links active -- height necessary for IE 5.5 */ #LinkBar a, #MenuBar a { display: block; height: 1.3em; } #Menu1 a:visited, #Menu2 a:visited, #Menu3 a:visited, #Menu4 a:visited, #Menu5 a:visited, #Link1 a:visited, #Link2 a:visited, #Link3 a:visited, #Link4 a:visited, #Link5 a:visited { color: #039; background: #f9f9f9; } #Menu1 a:link, #Menu2 a:link, #Menu3 a:link, #Menu4 a:link, #Menu5 a:link, #Link1 a:link, #Link2 a:link, #Link3 a:link, #Link4 a:link, #Link5 a:link { color: #039; background: #f9f9f9; } #Menu1 a:hover, #Menu2 a:hover, #Menu3 a:hover, #Menu4 a:hover, #Menu5 a:hover, #Link1 a:hover, #Link2 a:hover, #Link3 a:hover, #Link4 a:hover, #Link5 a:hover { color: #C00; background: #f9f9f9; }
The numbered series of ten paired #Link1 and #Menu1 declarations for the five menus are handled in a similar way by grouped selectors. The vital differences between these selectors, visibility, border-top and height are declared beneath and complete the illusion of the extensible drop-down panel.
The final declarations for .Title and #Header simply move these standard page components down further than normal to accommodate the height of the menus.
The specificity of the A:hover property in the drop-down menus is evidently being calculated differently in Netscape 6, compared with Opera 5 and Internet Explorer 5. Netscape 6.0 and 6.1 do not show the hover style, but this bug is fixed in Mozilla build 2001092003 and later.
Use CSS3 extension styles with Javascript to add subtle rounded corners and drop shadows in Firefox, Safari and Google Chrome. Set border-radius, box-shadow and other CSS3 styles by ID, class or tag name.