[an error occurred while processing this directive] [an error occurred while processing this directive]
Now updated for horizontal, vertical and tertiary menus.
This page describes the implementation details of our Lightweight (we think) Pop-Out menus using cross-browser DHTML, CSS and Javascript.
All Browsers are different. Case closed. But the W3C DOM has improved things (or is it just a high quality Gecko implementation) - which actually only makes the differences more annoying!
We have changed our cross-browser philosophy (big word) 'cos:
Here's what we are doing now and all the code reflects (more or less!!) this policy:
There is ton of stuff out there about the W3C DOM but the best, by far, that we found is in the 'Resources' side-bar under 'Life Savers' and in our links pages.
The holy grail of the HTML, XHTML and XML object worlds is the W3C Document Object Model DOM Versions 1 and 2 (see Resources and forget DOM 1).
Confusingly Microsoft uses two terms: the DHTML Object Model (a DOM) and the W3C'ish Document Object Model (another DOM). They are different. The DHTML Object Model was supported from IE4, the W3C DOM 'ish from IE 5.5+.
Our minimum browser choice is IE4 so we use the DHTML Object Model (backward compatibility is very strong with MSIE so all that crummy old code will still work in MSIE 6+).
The MSIE Event model 'bubbles-up' vs Gecko/NS 'top down' event model.
The Navigator 4.06+ world uses the idiosyncratic LAYERS, CSSP and Style sheet model (defined in the Javascript 1.3 documentation). Ground-breaking at the time - just plain quirky to-day. As noted above we are doing no new work for this browser. Our minimum browser support is NS 4.06+ so you will see LAYER and CSSP stuff lying around. It's Event Model includes the powerful ability to 'hook' events which has been carried over to Gecko (and the W3C Event Model).
A very W3C compliant browser which is a pleasure to work with and with some excellent documentation - normally the achilles heel of Open Source projects. If you are not using it you should be. The event model is largely based on the NS4.x philosophy but without the event generation limits.
We came to do the update for the version 5 browsers having read all the stuff about W3C DOM compatibility and thinking it would be a breeze - and it wasn't.
We have some simple text rollover effects and they work in both browsers (MSIE and Gecko) unmodified. Very impressive. One hour and the site was updated.
Then we tried our pop-outs and it was not so good - in fact it did not work at all. Our CSS definitions are consistent but the Javascript - no way. So we hit the web. Turns out that the W3C DOM 'event model' is not supported by MSIE and marginally by Gecko. See below what we actually had to do.
The holy grail of the Javascript world is ECMA-262 which defines only hardcore (non DOM) language features and provides a frame-work for a standard language that is vendor independent. A mercifully thin document. Though almost incomprehensible.
We are going to lay out our pages as follows:
NOTE: In the descriptions below you will be offered two forms of each file. A Cross-Browser version containing code/definitions for all browser families we support and which is conditionally generated using Apache Server Side Includes statements and a Browser specific version which shows you the code that is supplied for, and is unique to, the browser you are using.
The current implementation of our Cross Browser CSS definitions are here (loads in a separate window as a text file, use the 'save as' browser button to save as an .SHTML file) or you can view your browser specific Pop-Out menu CSS definitions here. They both load in a separate window so you can read the accompanying text and look at the code.
You will notice three major differences in CSS definition:
Point Size: e.g. 'n-l-o' and 'codegray' styles differ only in font point size on MSIE and Gecko/NS4.x. The rendering below 10pt is so poor on NS/Gecko that we generally have to add 1 more point for NS/Gecko than MSIE. Note: It is generally NOT a good thing to use an explicit point size but rather the relative values 'small' or 'x-small' etc. since it facilitates 'accessibility' options. Since there is no consistency in implementation of point size to 'small' etc. we use point size far more frequently than we should.
NS4.x Style Limitations 'popup' is defined for NS and 'n-p-o' is its equivalent style for MSIE/Gecko. If you run our Home Page with both browsers you will see a 'HighLight' text rollover in MSIE/Gecko but none in NS4.x. You cannot apply a 'class' style when changing an NS4.x layer value, you must instead apply separate 'bgColor' and 'Color' attributes to the layer. Since this defeats the objective of using CSS we chose to avoid using it completely in NS4.x.
NS4.x LAYERS 'p-n-h' is defined for MSIE/Gecko but not for NS4.x. The style attributes of 'p-n-h' are instead defined using the 'LAYER' TAG in NS4.x ('visibility="hidden"' is explicitly defined and 'position=absolute' is implicit in the LAYER definition. NOTE: You may read some strange and long winded explanations of 'relative' and 'absolute' positioning. Our simple view is that with 'relative' positioning (the implicit default for all TAGs) the browser gets to choose where to position stuff i.e. where it falls naturally 'in-line'. With 'absolute' you and your Javascript get to choose via the use of the 'top' and 'left' style properties.
The current implementation of our Cross Browser 'Primary' DHTML definitions are here (use the 'save as' browser feature to save as an .SHTML file) or you can view your browser specific 'Primary' Menu definitions here. They both load in a separate window so you can read the accompanying text and look at the code (wow - at the same time).
There are a number of points of difference here:
To get any 'onmouseover' effect in NS4.x you need either an 'A' (href) or a 'LAYER' TAG. We could have used an 'A' TAG with a 'dummy' href e.g. 'javascript();' or 'javascript://;' neither of which has negative effects except they appear on your status bar (a tad ugly).
To get full width for any 'text rollover highlight' in NS4.x you need to define a layer with 'width="100%"'. That clinched the decision to use the 'LAYER' TAG (even though we finally decided against use of 'highlighting' in NS4.x (see CSS notes above). Here we must point out a life-saving article on the topic of text rollovers in NS4.x. We managed to crash NS4.x repeatedly until we found this article.
We use 'onmouseover' and 'onmouseout' events in MSIE/Gecko (isW3C) and only an 'onmouseover' event in NS4.x. This is entirely due to lack of planning, foresight and understanding!! We coded the NS4.x pop-out first and just loved how we could turn on the mouse capture (using captureEvent(Events.MOUSEMOVE) see Javascript below). When we did the MSIE implementation we could not get the same effect so had to use the standard 'onmouseout' event. In retrospect using 'onmouseout' would work in NS4.x - all we would have to do is find the event object and read its mouse co-ordinates. Note: For Gecko browsers the 'onmouseout' call is to a null function - see javascript section below - we just left it in due to laziness.
The current implementation of our Cross Browser 'Secondary' (Pop-Out) DHTML definitions are here (loads in a separate window as a text file, use the 'save as' browser button to save as an .SHTML file) or you can view your browser specific 'Secondary' (Pop-Out) Menu definitions here. They both load in a separate window so you can read the accompanying text and look at the code.
This set of definitions includes the initially invisible tables that are 'pop'd out' when the user 'mouses over' the various menus. There are significant differences here reflecting the differing browser philosophies:
We use a 'DIV' TAG for MSIE/Gecko and apply the class style 'p-n-h' which gives each table the attributes 'position:absolute' and 'visibility:hidden' (among others). The initial values of both 'top' and 'left' are arbitrary (its hidden - does it matter where!). Note the 'onmouseout' event in each table cell for MSIE. See note above.
We use the 'LAYER' TAG (NS4.x only) and explicitly define in the layer the attributes we want (VISIBILITY, TOP and LEFT). The attribute POSITION="ABSOLUTE" is implicit in the use of LAYER (if you wanted POSITION="RELATIVE" you would use an 'ILAYER' TAG instead). The documentation says that 'DIV' TAGs can be used in NS4.x but we could never get them to work. NOTE: There are no defined 'onmouseout' events for NS4.x. See DHTML notes above.
The current implementation of our Cross Browser Javascript code is here (loads in a separate window as a text file, use the 'save as' browser button to save as an .shtml file) or you can view your browser specific Pop-Out Javascript code here. They both load in a separate window so you can read the accompanying text and look at the code.
The code mostly reflects the various differences in manipulation of the object models and consists of eight functions, pop() (all browsers), popdown() (Gecko/NS4.x only), clip()(MSIE/Gecko only), unpop() (MSIE/Gecko only), unpop() (Gecko/MSIE only), swapout() (MSIE only , null function for Gecko), popclean() (MSIE/Gecko only), mousemoved() (NS4.x only, provides same functionality as Gecko popdown()).
Note: The functions swap() and lock() are generic text rollover functions we use extensively, gotourl() is a simple redirect - none have anything to do with this article.
The function pop() takes three parameters 'p' (the menu level), 's' (the id value of the menus to be made visible) and 'axis' which may be 'h' = horizontal or 'v' = vertical. Primary, secondary and tertiary menus are are all identified with 'id="hx" or id="sx" values so the calling parameters are simple numbers. This function generates the 'clipping area' used by the swapout() or popdown() functions i.e the visible area covered by the 'Primary' and 'Secondary' menus. You will see various 'fudge' factors all over the place which provide various 'guard bands' after much experimentation. One day we will clean this code up and provide a reasonable explanation. When this function is called it now makes sure that all other menus are 'off' (via the popclean() function), 'cos we had menus getting stuck from time to time (a bug - no way!!). Finally to make this code generic we have used arrays to hold all the global objects and clip data. In theory this means we are unlimited in the menu levels we can support (oh really!).
In the NS4.x version of pop() you will find the 'captureEvent(Events.MOUSEMOVE)' which hooks the 'mousemove' events to the mousemoved() until you are out of the clipping area. In MSIE this is done with a standard onmouseout event. In Gecko we use a W3C obj.addEventListener() to the popdown() function.
The function swapout() is an MSIE only function (which does the same as the mousemoved()/popdown() functions of NS/Gecko). The purpose is to capture the current position of the mouse from the 'window.event' object and if it has moved OUT of the clipping area to 'pop-down' the relevant menu and turn off the highlight. The only other wrinkle of note is the use of the window.body.scrollTop and scrollLeft which are essential to ensure everything works when you scroll the page.
The function
popdown() in Gecko (and it's mousemoved() NS equivalent) is functionaly equivalent to swapout() of MSIE. Its purpose is to capture the current position of the mouse and if it has moved OUT of the clipping areas to 'pop-down' the 'Secondary' menu.
W3C'ish support We tried to use a single 'onmouseout='swapout();'' function but we couldn't find the mouse co-ordinates in Gecko in about 3 hours reading. Then we found the 'relatedObject' property but it did not provide reliable results in Gecko. Since MSIE is religious about backward compatibility we left its code untouched and now generate conditional code for Gecko only ('isW3C' and NOT 'isIE'). In the pop() function we set up the 'clipping area' as normal and then hook the onmouseout events for the menu areas using the addEventListener property into the popdown() function which automatically supplies the 'event' object from which we obtain the mouse co-ordinates. If we are outside the 'clipping area' we hide the relevant menus, change the 'className' properties and remove the 'onmouseout' events via the removeEventListener property of the object.
All a bit disappointing and maybe if we had a lot more time we could find a better solution.
That's all folks. I hope you have found this information and explanation useful or at least it has given you something to start thinking about 'lightweight' web features. Check our links pages for all the reference material (use Languages/Javascript and Web Resources/html_dhtm or css). If you have comments, questions, solutions to some of our problems or suggestions for improvements we would be delighted to hear from you. In the meantime we should really clean this stuff up...
[an error occurred while processing this directive]