Dynmenu, tutorial on Dynamic menus with DHTML  
Tutorial Files Images Features Feedback
 
português
 

On this page you will find a detailed description of each file used in this tutorial. Feel free to copy and paste the code to your own pages and adapt it to your needs.

There are excerpts of the files shown in the code and you can access the whole files by viewing their sources.

The Dynmenu is designed with modularity in mind. That's why most of the code is stored in separate files that are linked into the HTML pages. This will help you building the code for multiple pages and, especially, maintain, revise and update it later.

  Style sheet: dm.css
 

This file fulfils a double task:

  1. it defines the position and characteristics of the layers implementing the dynamic menus and
  2. it defines the styles of the HTML tags used.

Only the first function is relevant for the dynamic menus, but remember that is much wiser to use style sheets to code the visual layout of your pages than doing it inside the HTML pages: you make sure the design is consistent throughout the site and it there is only one file to modify when you update the site, instead of hundreds of pages to change.

Each dynamic menu is defined by a code similar to:

#dynmenu0 { position: absolute; top: 67; left:3; z-index:99; visibility:hidden; background-color:#CC0000; }

The elements on the line are the following:

#dynmenu0:
the name of the layer follows the hash sign (#).
I usually use a unique name ("dynmenu") for all layers followed by a number that is also used to refer to the menu in the array variables.
position:
position it is defined as absolute relative to the window co-ordinates - it could be relative to other layers - and the co-ordinates are given 3px (pixels) from the left margin and 67px from the top of the window; the z-index codes how layers are stacked if you use superimposed layers. There is no absolute value, only relative values: higher values put the layers on top; the code inside the <BODY></BODY> is always the bottom (lowest) layer.
Make sure the positions are accurate for best visual effect. One of the reasons of using the menus near the top-left corner is that is easier to assure that no other elements before it have variable size or depend on the window size, hindering the visual effect.
visibility:
states whether the layer is initially visible or hidden. Usually the menus are hidden, but you could leave one of them open by default to suggest their use to the visitors of your site, although this might seem redundant for most audiences.
background-color:
determines what is the background colour. If nothing is stated the background of the layer will be transparent. You can also define the background in the layer code.
I prefer this solution to make sure the layers are opaque. As you'll see, I made an exception in the "Features" menu for tutorial purposes. More on that in the Transparent background section.

In this tutorial I used five menus with equal width. Naturally, you could change the number, spacing and width of the menus. Just be sure to set their initial positions correctly.

I advise you not to constrain the sizes of the menus for maximum flexibility of the menu contents. If you want to constrain the width, use a table in the menu code and omit the height setting to accommodate more text, larger text or more menu entries.

There also additional parameters you can add to suit your tastes, such as:

border-width:1; border-style:solid; border-color:#404040;

  Functions: dm_func.js
 

This file holds

  1. the functions and the variables to show and hide the layers and
  2. the functions to change the roll-over images.

Only the former are relevant for the dynamic menus but the latter add an often appreciated - and now common - feature of image links.

The file begins with the definition of an Boolean array, with one entry per menu. I defined the menus by numbers, from 0 to 4, from left to right and the array follows the same sequence. If one layer is visible, the appropriate array entry is true, otherwise it is false.

Then, there is the definition of a time-out array. If the layer's visibility is dependent on an impending time-out, its ID is stored in the appropriate entry of the array. Otherwise the array value is meaningless. In this tutorial I use 5 menus, hence the number five. For the sake of generality, you should use a constant with the number of menus.


There are only to actions applied to the menus: show and hide, corresponding to the functions showMenu(idx) and hideMenu(idx).

The showMenu(idx) function receives the index of the menu (a whole number defined by the user) and sweeps all layers in a loop to check if any layer, different from idx is visible (the dynmenu[i] entry is "true"). If this occurs, the layer is hidden:

for(i=0;i<5;i++) if (dynmenu[i] && (i!=idx)) hideMenu(i);

The next action is to change layer visibility to "visible". However, the code must be forked to meet the different implementations of layers by the various browsers:

if(document.getElementById) document.getElementById("dynmenu"+idx).style.visibility='visible';
else if (document.all) eval("document.all.dynmenu"+idx+".style.visibility='visible';");
else if (document.layers) eval("document.dynmenu"+idx+".visibility='visible';");

The first line is interpreted by newer browsers that adhere to the World Wide Web Consortium (W3C, www.w3c.org) Document Object Model specification. This is the case for Netscape Navigator 6 and later and Microsoft Internet Explorer 6 and later. The name of the "element" is composed by "dynmenu" plus the index "idx" and its property .style.visibility is set to "visible".

The second line is addressed to Microsoft Internet Explorer 4 and 5 releases. The name of the "element" is composed by "dynmenu" plus the index "idx" and its property .style.visibility is set to "visible". In this case, the layers are found under the document.all object array.

The third line is addressed to Netscape Navigator 4 release. The name of the "element" is composed by "document.dynmenu"+idx and its property visibility is set to "visible". In this case, the layers are found under the document.layers object array.

Then, the dynmenu array is updated, by setting the entry to true:

dynmenu[idx]=true;

Finally, a timer is set: if the user does not select one entry within 8000 milliseconds, the visible layer will be automatically hidden:

timerID[idx]=setTimeout("hideMenu("+idx+")",8000);

This feature helps novice users that are not comfortable with layers and want to view the page without being disturbed by superimposed content. This solution has a shortcoming, though: if the user keeps the pointer over the dynamic for longer than the specified time, the menu will disappear and the user will have to return to the top tab to show it again. Thus, the time-out should balance the two conflicting goals.

Other implementations could solve this issue by automatically hiding the menu when the pointer is not over it. However, I prefer this solution because it is simpler for novice users and experienced users click the desired menu entry at once without any disturbance.


The hideMenu(idx) function is a "mirror" of showMenu(idx). It clears the timeout set by showMenu(idx). If this timeout has already expired, the browser ignores the command:

clearTimeout(timerID[idx]);

Then, it sets the visibility property of the idx-layer to "hidden". Again, the code must be forked to accommodate the differences among browsers:

if(document.getElementById) document.getElementById("dynmenu"+idx).style.visibility='hidden';
else if (document.all) eval("document.all.dynmenu"+idx+".style.visibility='hidden';");
else if (document.layers) eval("document.dynmenu"+idx+".visibility='hidden';");

The first line is interpreted by the browsers that adhere to the World Wide Web Consortium Dynamic HTML specification.

The second line is addressed to Microsoft Internet Explorer 4 and 5 releases. In this case, the layers are found under the document.all object array.

The third line is addressed to Netscape Navigator 4 release. In this case, the layers are found under the document.layers object array.

Finally, the dynmenu array is updated, by setting the entry to false:

dynmenu[idx]=false;


The roll-over image effect is implemented with two functions: imgOver(imgHndl) and imgOut(imgHndl). The first is associated to the onMouseOver event while the second is associated to the onMouseOut event.

When the pointer (also known as the cursor) passes over an image with the roll-over the source of the image is changed to a filename equal to the current filename with the "ov" suffix: if the source of an image is the "XYZ.jpg" file, the source of the roll-over image is "XYZov.jpg". Thus, every roll-over image's source must be duplicated with a source with the "ov" suffix.

The imgOver() function code is explained below:

imgHndl.src=imgHndl.src.substr(0,imgHndl.src.length-4)+"ov"+imgHndl.src.substr(imgHndl.src.length-4);

  1. The image handler is passed to the imgOver(imgHndl) function.
  2. The source property is extracted from the handler and put into a string.
  3. This string is split in two sub-strings. The first part runs from the beginning (offset set to 0) to the length of the string except the last four characters; these four characters are the second sub-string, running from this point (offset set to the length-4) to the end of the string and correspond to the image extension, usually ".jpg", ".jp2", ".gif" or ".png".
  4. The new image source is set by joining the first sub-string with the "ov" suffix with the extension.

When the pointer leaves an image with the roll-over the source of the image is restored to the original filename, without the "ov" suffix by means of the imgOut(imgHndl) function:

imgHndl.src=imgHndl.src.substr(0,imgHndl.src.length-6)+imgHndl.src.substr(imgHndl.src.length-4);

  1. The image handler is passed to the imgOut(imgHndl) function.
  2. The source property is extracted from the handler and put into a string.
  3. This string is split in two sub-strings. The first part runs from the beginning (offset set to 0) to the length of the string except the last six characters; the second sub-string holds the extension (offset set to the length-4 and running to the end of string).
  4. The new image source is set by joining the first sub-string with the extension.

This code is general purpose and is independent of the paths of the images. The only requirements are the use of the "ov" suffix and the three letter extensions.

You should be aware that only the image's source is changed. The size of the original image is kept, regardless of the actual size of the roll-over image.

  Menu entries: dm_en.js
 

The dm_en.js file holds the content of the dynamic menus. If you're creating a multilanguage site such as this portuguese/english one, the two previous files could be common to all languages since they contain just the code and only this file reflects the content. The dm_en.js file holds the english menus and the links to the english pages, whereas the dm_po.js file holds the portuguese menus and the links to the pages in portuguese.

The coding is straightforward. The file contains a single JavaScript statement to write the HTML code in the document:

document.write('<DIV ID="dynmenu0">
<TABLE WIDTH="134" BORDER="1" BORDERCOLOR="#FFEEEE" CELLPADDING="2" CELLSPACING="0">
<TR><TD class="tabm" ><A HREF="tutorial.html#02">Introduction</A></TD></TR>
<TR><TD class="tabm" ><A HREF="tutorial.html#03">Modularity</A></TD></TR>
<TR><TD class="tabm" NOWRAP><A HREF="tutorial.html#04">Browser constraints</A></TD></TR>
<TR><TD class="tabm" NOWRAP><A HREF="tutorial.html#05">Layers explained</A></TD></TR>
<TR><TD class="tabm" NOWRAP><A HREF="tutorial.html#06">Events explained</A></TD></TR>
<TR><TD class="tabm" NOWRAP><A HREF="tutorial.html#07">How it works</A></TD></TR>
<TR><TD class="tabm"><A HREF="tutorial.html#08">Conclusion</A></TD></TR></TABLE></DIV>');

The example above shows the code for a single menu. The other menus are similar.

The paths of the links shown on this example are relative; if you want to use the same dm_en.js file for pages spread across multiple folders/directories, you must use one of two methods:

  1. Create a new dm_en.js for each folder/directory, updating the relative paths
  2. Using absolute paths from the root of the site.

The latter method is more efficient but the debug of the site offline becomes harder, unless you put your site on one root of the file system (in MicroSoft environments, this is a drive-letter).

I advise you to the perform the line wrapping of the code manually because you can not use line breaks in JavaScript statements. In spite of the appearance of the code sample above, I use no line breaks in the dm_en.js file. If the line length exceeds the limits of your word processor use a document.write() statement per layer.

  HTML pages
 

The three previous files contain the core of the dynamic menus. In the HTML pages, you just need to link the files and add the event handlers. Since all files have equal implementations of the dynamic menus, only the relevant sample of codes is described:

<link rel="stylesheet" href="dm.css" type="text/css">
This line must be added to the <HEAD></HEAD> section. It provides the dynamic menus settings and the styles definitions.
<SCRIPT LANGUAGE="JavaScript1.2" TYPE="text/javascript" SRC="dm_func.js"></SCRIPT>
This line must be added to the <HEAD></HEAD> section. It provides the JavaScript functions that show and hide the dynamic menus and the image roll-overs.
<SCRIPT LANGUAGE="JavaScript1.2" TYPE="text/javascript" SRC="dm_en.js"></SCRIPT>
This line must be added outside the <HEAD></HEAD> section and outside the <BODY></BODY> section. You could add it between both of them or after the <BODY></BODY> section, before the closing </HTML>.
It provides the content of the dynamic menus: the entries and their respective links.
<img src="../../02/icon/vela2.png" onMouseOver="imgOver(this)" onMouseOut="imgOut(this)" width="74" height="40" border="0">
This line does not concern the dynamic menus but the image roll-overs. The onMouseOver and onMouseOut events must be associated to the image instead of the link, to make sure that the "this" handler refers to the image. The file source will be extracted from this handler.
<td bgcolor="#CC0000" width="110" class="tab"><a href="tutorial.html" onMouseOver="showMenu(0)">Tutorial</a></td>
This is a sample line of the code used to show one dynamic menu - in this case, the first one with idx=0 (see Functions: dm_en.js above).
Notice that the dynamic menu appears in response to the onMouseOuver event but there is no onMouseOut event. In fact, the dynamic menu is hidden when the user follows the link to another page or when the timeout set by showMenu(idx) expires, triggering the hideMenu(idx) function (see Functions: dm_en.js above).
The remaining menu tabs are coded likewise, you just need to change the index in the showMenu() call.

And the implementation of the dynamic menus is completed... Simple, wasn't it ?

©2003 João Gomes Mota
Home, Inicio  → WEB DESIGNJAVASCRIPT, DHTML
Written on September 2003. inicio da página