Netscape DevEdge Redesign: JavaScript
Introduction
The initial launch of
DevEdge (http://devedge.netscape.com/)
as a separate site from the
DevEdge Archive (http://developer.netscape.com/)
in August 2002 maintained a great degree of compatibility with
legacy browsers such as Netscape Communicator 4.x and Internet Explorer 4.x.
This backward compatibilty however limited the nature of the site's
design and prevented the use of more advanced features.
One of the goals of the Netscape DevEdge Redesign was to illustrate how the W3C web standards can benefit web developers. Backward compatibility with older browsers was not a goal and has opened the door to adding some interesting features which illustrate the possibilities of advanced CSS and JavaScript.
Menus
One of the more popular uses of Dynamic HTML is to provide a rich navigation interface for web sites through the use of menus. Many different implementations of Dynamic HTML menus are available.
Typical menus implemented using Dynamic HTML have fairly large footprints, require visitors to enable JavaScript, are constructed on the fly, are not accessible and are difficult for average web authors to implement and maintain. For these as well as other reasons, many sites do not offer a rich navigation interface to their visitors.
We decided that using standards to implement a re-usable, maintainable and accessible menu for DevEdge would help educate web developers about the benefits of standards-based web development.
Pure CSS Menus
During 2002 Eric A. Meyer, Mark Newhouse and others began investigating the use of unordered lists and CSS to provide navigational help on web sites. This lead to the idea of implemented menus using only CSS 2 without the need for cross-browser JavaScript. This was possible for the first time due to the level of support achieved for the necessary features of CSS 2 in Netscape Gecko-based™ browsers such as Mozilla 1.0 and Netscape 7.x.
The possibility of providing the rich experience of Dynamic HTML without having to worry about cross-browser JavaScript issues with the added advantages of easy maintainance and increased accessibility were compelling reasons to investigate the use of pure CSS menus on DevEdge.
Example 1 - Pure CSS Menu
This example uses an unordered list containing the choices for
a simple one-level pull down menu. CSS rules are applied to
the unordered list through the use of the class name nde-menu-system
and submenus are identified via the use of the class name submenu.
<ul class="nde-menu-system">
<li><a href="#">Link</a></li>
<li class="submenu">
<a href="#">Submenu</a>
<ul>
<li><a href="#">Subitem 1</a></li>
<li><a href="#">Subitem 2</a></li>
</ul>
</li>
</ul>
The basic layout and functionality of the menu are achieved through CSS
rules which display the top-level list items inline, while
attaching different CSS rules to submenus through the use of CSS 2
:hover rules which are responsible for opening
and closing the submenus. Other CSS rules serve the role of smoothing
out the differences in the implementation of the CSS 2 specification
between Netscape Gecko, Opera and Internet Explorer.
Browser Comparison
Netscape Gecko-based browsers such as Netscape 7.x and Mozilla
on all platforms as well as Opera 7 on Windows display the top-level items
inline and open and close the submenu when the mouse hovers over the
top-level Submenu item.
Note that Netscape 7.x
requires the top be set in the ul.nde-menu-system li ul
css rule in order to position the submenus properly. You may need to adjust
this value if you reuse this example on your own site.
Note also the difference in appearance between Netscape Gecko-based browsers
and Opera 7.
Netscape 6.x on all platforms and Internet Explorer 5.5+ on Windows can display the top-level items
inline however due to their lack of support for :hover
on arbitrary elements they can not display the submenu.
Pure CSS menus have some compelling advantages:
- Ease of maintenance
- Accessibility
- Lightweight
- Navigation still possible in downlevel browsers which do not support CSS 2
- Not dependant upon JavaScript being enabled
Pure CSS menus also have disadvantages:
-
Lack of full support by Internet Explorer
-
Differences between the implementations of CSS 2 in different browsers can lead to differences in appearance and behavior in pages with layout more complicated than our simple example such as the redesigned pages on DevEdge.
To see this in action, open Netscape 7.01, disable JavaScript and load DevEdge. Note how the menus at the top of the page continue to work without serious degradation. Then open Opera 7, disable JavaScript and load DevEdge. Note how the submenus open displaced much farther down the page.
Hybrid CSS-JavaScript Menus
While the promise of pure CSS menus was compelling, the actual behavior of the browsers which visit DevEdge would mean that many of our visitors would not receive a positive experience if we relied solely on CSS to implement our menus.
A compromise approach was reached where we would provide a pure CSS menu which could be used by any CSS 2 capable browser without JavaScript enabled but would use JavaScript to emulate the CSS 2 features which were lacking in Internet Explorer and other browsers. At the same time, JavaScript could be used to smooth over implementation differences between CSS 2 compliant browsers.
The main features of CSS which needed to be emulated in JavaScript are:
- Selectors
-
Selectors in CSS determine to which elements specific CSS rules are applied. JavaScript and the W3C DOM Core API can be easily used to walk the unordered list and to apply specific style rules using the W3C DOM Style APi.
- :hover on arbitrary elements
-
:hoverCSS rules can be emulated through the use of mouseover and mouseout event handlers implemented in JavaScript attached to the appropriate elements. These event handlers can use the W3C DOM Core, DOM Style APIs to manipulate the appearance and structure of a document to reproduce the same behavior as accomplished through pure CSS.
Example 2 - Hybrid CSS-JS Menu
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="cssjsmenudhtml.css">
<link rel="stylesheet" type="text/css" href="cssjsmenuhover.css" id="hoverJS">
<script type="text/javascript" src="dhtml.js"></script>
<script type="text/javascript" src="cssjsmenu.js"></script>
<script type="text/javascript">
<!--
function init()
{
cssjsmenu('navbar');
if (document.getElementById)
{
var kill = document.getElementById('hoverJS');
kill.disabled = true;
}
}
// -->
</script>
</head>
<body onload="init()">
<h1>Example 2 - Hybrid CSS-JS Menu</h1>
<div id="navbar">
<ul class="nde-menu-system">
<li><a href="#">Link</a></li>
<li class="submenu">
<a href="#">Submenu</a>
<ul>
<li><a href="#">Subitem 1</a></li>
<li><a href="#">Subitem 2</a></li>
</ul>
</li>
</ul>
</div>
</body>
</html>
This example extends Example 1 by
-
Separating the CSS rules into two different external stylesheets: cssjsmenudhtml.css and cssjsmenuhover.css.
cssjsmenudhtml.css contains the basic rules which define the menu.
cssjsmenuhover.css contains only those rules related to
:hovereffects. Note the work around for Internet Explorer's bug where it propagate events into elements which simply visually cover other elements but do not contain them.This separation allows browsers with JavaScript enabled to disable the stylesheet containing the CSS
:hoverrules and to replace them with equivalent behavior implemented using event handlers. Disabling the CSS:hoverbehavior when using the JavaScript version of the hybrid menu is important since there can be unwanted interactions if both are active at the same time. -
Placing a
DIVwithIDattribute around theULcontaining the menu. This allows the menu to be quickly located using the W3C DOM Coredocument.getElementById()method. -
Incorporating two different external JavaScript files which are used to implement the JavaScript implementation of the hybrid CSS-JS menu: dhtml.js and cssjsmenu.js.
- dhtml.js
-
contains several functions which are used to get and set element positions and to determine whether one element contains another. Note that the non-standard properties
HTMLElement.offsetLeft,HTMLElement.offsetTop,HTMLElement.offsetParentare used to obtain the position of elements on the page. Although these properties were initially introduced by Microsoft Internet Explorer and are not standard, they are supported by Netscape Gecko-based browsers as well as Opera 7 and are quite useful. - cssjsmenu.js
-
contains the main function used to convert a pure CSS Menu into a Hybrid CSS-JS Menu. The function
cssjsmenu(menuid)locates theDIVwhich contains the menu's unordered list, walks down the DOM of the unordered list converting the style attributes of theULandLIelements into a form which can be used by themouseoverandmouseoutevent handlers, and attaches the appropriate event handlers to mimic the:hoverCSS rules.
-
Defining an
onloadevent handler which will call thecssjsmenufunction to enable the JS-based menu and to disable the stylesheet containing the pure CSS Menu's:hoverrules.
Browser Comparison
Note that the Hybrid CSS-JS Menu is supported by Netscape Gecko-based browsers Netscape 6.x, Netscape 7.x and Mozilla 0.9.4+ (All platforms), Opera 7 (Windows) and Internet Explorer 5.5+ (Windows).
Example 3 - Hybrid CSS-JS Menu with Style
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="cssjsmenudhtml.css">
<link rel="stylesheet" type="text/css" href="cssjsmenuhover.css" id="hoverJS">
<link rel="stylesheet" type="text/css" href="cssjsmenustyle.css"">
<script type="text/javascript" src="dhtml.js"></script>
<script type="text/javascript" src="cssjsmenu.js"></script>
<script type="text/javascript">
<!--
function init()
{
cssjsmenu('navbar');
if (document.getElementById)
{
var kill = document.getElementById('hoverJS');
kill.disabled = true;
}
}
// -->
</script>
</head>
<body onload="init()">
<h1>Example 3 - Hybrid CSS-JS Menu with Style</h1>
<div id="navbar">
<ul class="nde-menu-system">
<li><a href="#">Link</a></li>
<li class="submenu">
<a href="#">Submenu</a>
<ul>
<li><a href="#">Subitem 1</a></li>
<li><a href="#">Subitem 2</a></li>
</ul>
</li>
</ul>
</div>
</body>
</html>
This example extends Example 2 by adding another stylesheet, cssjsmenustyle.css to customize the appearance of the menu and menu items.
How the Hybrid CSS-JS Menu is used on DevEdge
DevEdge uses the Hybrid CSS-JS Menu to implement both the pull-down menu found at the top of every page and the customize menu which allows visitors to select their favorite themes.
Conclusion
Hybrid CSS-JS menus provide a light-weight, accessible, easily maintained method of adding simple pull-down menus to your site. Please feel free to reuse these menus on your own site.
There are many different approaches to providing modern browsers with dynamic menus. For additional study, I recommend BrainJar.com's Menu Bar and gazingus.org's Using Lists for DHTML menus.
