AcmeMenu v2.7 Mack Pexton May 3, 2005

Introduction
Status of this Document
Download
Definitions
Instructions

Manual Menus
Simple Menus
Inline Menus
Form Menus

Auto Menus
Drop Down Menus
Vertical Menus
Push Up Menus
System MenusCool stuff
Fixed Menus
Mack Menus
Configuration Variables
Suggestions
Testing Menus
Top

Introduction

There are several techniques and methods for constructing cross-browser drop-down DHTML menus. Most of them require that the exact location of the menus be pre-determined on the page, or they use only images for the menu selections, or they are constructed by JavaScript after the page is loaded. My work with the AcmeBase Project involves writing programs that write DHTML, and I found the current methods to be clumsy to use to construct menus with programs. The following describes my solution to rendering DHTML menus on web pages and provides several examples of their use.

These menus are:

Powerful.
All types of DHTML menus can be constructed: drop-down, pop-up, pop-every-which-way. No limits are imposed on the number of menus, the number of submenus, or the number of items on any one menu. Menus can be placed anywhere in the document and they can contain any HTML element, including images and forms.
Easy to define.
Menus are defined using standard HTML <div> tags, <a> tags, and possibly <table> or <img> tags. They are easy to layout with PHP or any other server-side program.
Easy to maintain.
Menus are defined right in the HTML document, so any tool used to change the document can be used to change the menus. Any changes to the menus are immediately applied — there are no extra programs to run or extra files to change. Automated tools like link checkers work as expected because the menu items are usually defined as simple <a> tags.
Easy to use.
Menu operations are timed so that the menus work naturally. Mouse clicks are monitored so that menus "freeze" open or close if the mouse is clicked outside of their borders.
Efficient.
Menus are dynamically built from the HTML document as they are needed and cached for reuse. The menu scripts can be used on other web pages menus without needing to be downloaded again by the browser.
Search engine friendly.
All menu selections are simple <a> tags that are easily digested by search engine spiders, just like any other link in the document. The links are not hidden in the JavaScript programming or in separate configuration files. That also means software checking for broken links also works as expected.

These menus work with Internet Explorer 5+, Netscape 6+, Opera 5+, Konqueror 3+, Safari 1+, Mozilla 1.2+, and Firefox 0.6+. Over a dozen browsers have been tested. See Browser Notes for a complete list.

Top

Status of this Document

This document is the primary description of AcmeMenu. It is intended to 1) provide instructions to constructing DHTML menus, 2) provide working examples of their use, and 3) provide code examples which can be copied and pasted into other documents to be used as templates setting up other menus. This document grew with the software and has become quite large. Originally it was used to test the menus, but now the menus can be tested using the testmenu.htm page. This document is the first to change as the menu software is revised.

Top

Download

There are three versions of the JavaScript menu functions. One is the original source code complete with comments and debug statements. The second version is the first without comments or debug which makes it half the size of the source file and saves download time. The third version is a commercial version that is even smaller in size and is available for $59.95.

AcmeMenu_source.js JavaScript source code complete with comments and debug. (88.2KB)
AcmeMenu.js JavaScript without comments or debug statements. (38.1KB)
AcmeMenu.zip All the files used to render this document. (64.3KB)

This is open software and is licensed under the terms of the GNU General Public License.

Top

Definitions

A menu, as used here, is a <div> or a <table> tag with an id attribute set to the menu's name.

A menu header is an <a> tag that has 1) an id attribute, and 2) a href attribute set to:

javascript:menu('menu_id','menu_header_id')

A menu item is an <a> tag that is within a menu or submenu.

A submenu is the same as a menu, just a <div> or <table> tag with an id attribute.

A submenu header is a menu item (an <a> tag within a menu) that has its href attribute set to:

javascript:submenu('submenu_id')
Top

Instructions

Setting up DHTML menus is a three or four step process.

  1. Copy the following statement into your document between the <head> and </head> tags.

    <script src="AcmeMenu.js" type="text/javascript"></script>
  2. Define your menu in the HTML source file. Menus are simply <div> or <table> tags with enclosed <a> tags. Each of the menus have a different ID to differentiate them. Most of the menus below are similar to this example:

    <!-- Menu Header -->
    <a href="javascript:menu('examplemenu','examplemenu_head')"
     id="examplemenu_head" class="menu-head">Menu</a>
    
    <!-- Main Menu -->
    <div id="examplemenu" class="menu">
    <a href="javascript:submenu('examplesubmenu')">Submenu</a>
    <a href="javascript:submenu('examplesubmenu2')">Submenu 2</a>
    <hr>
    <a href="javascript:self.print()">Print</a>
    <a href="javascript:self.close()">Exit</a>
    </div>
    
    <!-- Submenu Menu -->
    <div id="examplesubmenu" class="menu">
    <a href="http://www.nowhere.com">Go Nowhere</a>
    <a href="http://www.somewhere.com">Go Somewhere</a>
    </div>
    
    <!-- Submenu 2 Menu -->
    <div id="examplesubmenu2" class="menu">
    <a href="http://www.north.com">Go North</a>
    <a href="http://www.south.com">Go South</a>
    <a href="http://www.east.com">Go East</a>
    <a href="http://www.west.com">Go West</a>
    </div>
    
  3. The next step, which is not necessary for manual menus, is to initialize your menus with a small script that defines some configuration variables and calls the make_menu() function. Its arguments are the ID of the menu and the ID of the menu header.

    <script language="JavaScript" type="text/javascript">
      make_menu('examplemenu','examplemenu_head');
    </script>
    

    If there are more than one set of menus on a page, call the initialize_menus() function before setting up the next set.

  4. The final step is to define the CSS styles for the menus and place them in between the document's <head> and </head> tags. A simple CSS example is:

    <style type="text/css">
    <!--
    .menu { position:absolute; visibility:hidden;
            background-color:lightyellow; border:solid black 1px; }
    .menu a         { display:block; width:100%; }
    .menu a:hover   { text-decoration:none;
                      background-color:lightgrey; }
    -->
    </style>
    

    As a general rule, the menu <div> tags have the CSS styles of position:absolute; and visibility:hidden; so they can be positioned and so their initial display is hidden. If you are using <table> tags for the menus, then they should have the display:block; setting too. The <a> tags usually have the styles of display:block;, and for Internet Explorer, width:100%;.

The examples below show the Javascript, the stylesheet settings, and some sample HTML code so that you can copy them and paste them into your document to use as templates setting up your own menus.

Top

Manual Menus

The simplest menus are referred to here as "manual" menus. The buttons need to be clicked by the user in order to activate them. Clicking the buttons again or clicking anywhere outside the menus hides them.

Top

Simple Menus

Menu

The display of the menu and menu header is determined by CSS styles.

The actual location of a manual menu on the page needs to be pre-determined and specified in the CSS stylesheet. Its location is usually relative to the entire document, but it can be wrapped in another <div> tag with a style setting of position:relative;.

Notice the Menu button remains highlighted after it is clicked. That is because a class menu-head has been assigned to the button. If the software detects that a CSS class has been assigned to a menu (or submenu) header, it will reassign the class to a name that is the original name with the string "-hilite" appended to it. In the above example, the class name assigned to the Menu button when clicked is "menu-head-hilite". This allows the selected path to remain highlighted as the user operates the menus, and is illustrated below with the Vertical Menus and System Menus.

Simple menus do not need a script.

Here is the style sheet used for the above menu.
<style type="text/css">
<!--
/* Menu Styles */
div.menu {
	visibility:hidden;
	position:absolute;
	color:black;
	background-color:lightyellow;
	border:solid black 1px;
	}

div.menu a         { display:block; width:100%; }
div.menu a:link,
div.menu a:visited,
div.menu a:active,
div.menu a:hover   { color:black; text-decoration:none; }
div.menu a:hover   { background-color:lightgrey; }

a.menu-head,
a.menu-head:link,
a.menu-head:visited,
a.menu-head:hover,
a.menu-head:active,
a.menu-head-hilite,
a.menu-head-hilite:link,
a.menu-head-hilite:visited,
a.menu-head-hilite:active,
a.menu-head-hilite:hover {
	display:block;
	text-align:center;
	color:black;
	border:solid black 1px;
	width:75px;
	}
a.menu-head        { background-color:lightgrey; color:black; }
a.menu-head:hover,
a.menu-head-hilite { background-color:lightyellow; color:black; }

#manmenu     { left:80px;  top:0px; width:150px; }
#mansubmenu  { left:237px; top:0px; width:100px; }
#mansubmenu2 { left:237px; top:0px; width:100px; }
-->
</style>
Here is the HTML code used to construct the above menu.
<!-- Menu Header -->
<a href="javascript:menu('manmenu','manmenu_head')"
class="menu-head" id="manmenu_head">Menu</a>

<!-- Main Menu -->
<div id="manmenu" class="menu">
<a href="javascript:submenu('mansubmenu')">Submenu</a>
<a href="javascript:submenu('mansubmenu2')">Submenu 2</a>
<hr>
<a href="javascript:self.print()">Print</a>
<a href="javascript:self.close()">Exit</a>
</div>

<!-- Submenu Menu -->
<div id="mansubmenu" class="menu">
<a href="http://www.nowhere.com">Go Nowhere</a>
<a href="http://www.somewhere.com">Go Somewhere</a>
</div>

<!-- Submenu 2 Menu -->
<div id="mansubmenu2" class="menu">
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>

Top

Inline Menus

The above link used to show the style sheet for the manual menu and the next link below are examples of "inline" menus. They are a degenerative form of a menu that does not overlay the document, but instead expands the document when shown.

An inline menu is simply a menu header (an <a> tag) followed by a menu (a <div> tag). Whereas other menus specify the style position:absolute;, inline menus omit that setting. Inline menus also work best if you specify a third argument to menu() that causes the menu to stay open when the user clicks somewhere else on the document. For example, the href attribute of the menu header's <a> tag is:

<a href="javascript:menu('menu_id','menu_header_id',true)"
 id="menu_header_id" class="example">...</a>

Inline menus do not need a script.

Here is the style sheet used for these inline menus.
<style type="text/css">
<!--
div.example
	{
	display:none;
	padding:1ex 2ex;
	border:solid black 1px;
	}
a.example-head,
a.example-head-hilite
	{
	display:block;
	padding:0px 3ex;
	background-position:left top;
	background-repeat:no-repeat;
	}
a.example-head        { background-image:url(dtriangle.gif); }
a.example-head-hilite { background-image:url(utriangle.gif); }
-->
</style>
Here is the HTML code used to construct this inline menu.
<a href="javascript:menu('ex_inline_html','ex_inline_html_head',true)"
   id="ex_inline_html_head"
   class="example-head"
>Here is the HTML code used to construct this inline menu.</a>

<div id="ex_inline_html" class="example">

<!-- The contents of the inline menu go here. -->

</div>

Unfortunately these inline menus do not work well with Opera 5 or Opera 6.

Top

Form Menus

Form

Form

First
Second
Third
Check One Two

Menus work well as pop-up forms. The contents of a menu can be anything, not just <a> tags. That even holds true for the Auto Menus described next because the forms "freeze" open when clicked. Look at the Drop Down Menus under Menu1 below for another example of a pop-up form.

Note: Using this software only for the manual menus described above is analogous to hammering a nail with a sledgehammer. Most of the software is devoted to locating an element pointed to by the mouse, determining its dimensions and coordinates, and placing another document element next to it. The above manual menus can be implemented with much smaller programs. However, if the software has already been downloaded on a previous page, it is a useful library to use. Plus the operation of the manual menus do not interfere with the operation of the Auto Menus described next.

Top

Auto Menus

Menus come alive when you call the make_menu() function. Simply hovering over the menu header with the mouse automatically pops up the menu.

Calling make_menu() initializes the top level menus and locates their headers. Submenus are built dynamically as they are needed. That differs from the manual menus above, which scan for all enclosed submenus the first time they are invoked.

Top

Drop Down Menus

Menu1 Menu2 Menu3

Form

First
Second
Third
Check One Two

The above menus are defined just like the first manual menu. The only difference is that they are setup by executing the following JavaScript:

<script language="JavaScript" type="text/javascript">
  make_menu('menu1','menu_head1');
  make_menu('menu2','menu_head2');
  make_menu('menu3','menu_head3');
</script>

The styles used to render the drop down menus are the same as those used to describe the simple menus above.

Here again is the style sheet used for these drop down menus.
<style type="text/css">
<!--
div.menu {
	visibility:hidden;
	position:absolute;
	color:black;
	background-color:lightyellow;
	border:solid black 1px;
	width:125px;
	}

div.menu a         { display:block; width:100%; }

div.menu a:link,
div.menu a:visited,
div.menu a:active,
div.menu a:hover   { color:black; text-decoration:none; }

div.menu a:hover   { background-color:lightgrey; }

a.menu-head,
a.menu-head:link,
a.menu-head:visited,
a.menu-head:hover,
a.menu-head:active,
a.menu-head-hilite,
a.menu-head-hilite:link,
a.menu-head-hilite:visited,
a.menu-head-hilite:active,
a.menu-head-hilite:hover {
	display:block;
	text-align:center;
	color:black;
	border:solid black 1px;
	width:75px;
	}

a.menu-head        { background-color:lightgrey; }

a.menu-head:hover,
a.menu-head-hilite { background-color:lightyellow; }

/* Form */
div.formmenu {
	visibility:hidden;
	position:absolute;
	text-align:center;
	color:black;
	background-color:lightyellow;
	border-color:lightgrey;
	border-style:solid;
	border-width:1px;
	padding:3px;
	width:325px; 
	}
-->
</style>
Here is the HTML code for the menu bar and the first menu.

<!-- Menu Bar -->
<center>
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<a href="javascript:menu('menu1')"
  id="menu_head1" class="menu-head">Menu1</a>
</td>
<td>
<a href="javascript:menu('menu2')"
  id="menu_head2" class="menu-head">Menu2</a>
</td>
<td>
<a href="javascript:menu('menu3')"
  id="menu_head3" class="menu-head">Menu3</a>
</td>
</tr>
</table>
</center>

<!-- Main Menu 1 -->
<div id="menu1" class="menu">
<a href="javascript:submenu('submenu3')">Submenu</a>
<a href="javascript:submenu('submenu4')">Submenu 2</a>
<hr>
<a href="javascript:submenu('formmenu2')">Form<img
  src="star.gif" border="0" alt="Cool stuff"></a>
<hr>
<a href="javascript:self.print()">Print</a>
<a href="javascript:self.close()">Exit</a>
</div>

<!-- Submenu Menu -->
<div id="submenu3" class="menu">
<a href="http://www.nowhere.com">Go Nowhere</a>
<a href="http://www.somewhere.com">Go Somewhere</a>
</div>

<!-- Submenu 2 Menu -->
<div id="submenu4" class="menu">
<a href="javascript:submenu('submenu41')">Submenu 3</a>
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>

<!-- Form Menu -->
<div id="formmenu2" class="formmenu">
<form action="javascript:void 0">
<h3>Form</h3>
<table>
<tr>
<th>First</th>
<td><input type="text" name="first" size="25"></td>
</tr>
<tr>
<th>Second</th>
<td><textarea rows="2" cols="18"></textarea></td>
</tr>
<tr>
<th>Third</th>
<td><select>
 <option></option>
 <option>First example choice</option>
 <option>Second example choice</option>
 <option>Third example choice</option>
</select></td>
</tr>
<tr>
<th></th>
<td><input type="checkbox" value="y"> Check
<input type="radio" name="testradio" value="y"> One
<input type="radio" name="testradio" value="y"> Two</td>
</tr>
</table>
<br><input type="submit" value="Submit">
</form>
</div>

Top

Vertical Menus

 
Go Nowhere Go Somewhere
Submenu 3 Go North Go South Go East Go West
Go North Go South Go East Go West
Go Nowhere Go Somewhere
Submenu 3 Go North Go South Go East Go West
Go North Go South Go East Go West

The menu header for a menu is optional. If a menu does not have a header, it needs to be visible -- it cannot pop up. This makes vertical menus easy to construct. They are simply the main menu without the CSS style display:none; or visibility:hidden;.

The above left and right menus are defined just like the auto menus above except that there isn't a menu header. They are setup by executing the following JavaScript, first the left and then the right. Note that the second argument to make_menu() is now not needed.

<script language="JavaScript" type="text/javascript">
  make_menu('leftmenu');
</script>
Here is the style sheet used for the left menu.
<style type="text/css">
<!--
/* Left Vertical Menus */
div.leftmenu,
div.leftsubmenu {
	background-color:#DDDDDD;
	border-width:1px;
	border-style:solid;
	border-color:black;
	text-align:left;
	padding:2px;
	}
div.leftmenu { position:relative; }
div.leftsubmenu {
	position:absolute;
	visibility:hidden;
	}

div.leftmenu a         { display:block; width:100%; }
div.leftmenu a:link,
div.leftmenu a:visited,
div.leftmenu a:hover,
div.leftmenu a:active  { color:black; text-decoration:none; }
div.leftmenu a:hover   { background-color:lightyellow; }

div.leftsubmenu a         { display:block; width:100%; }
div.leftsubmenu a:link,
div.leftsubmenu a:visited,
div.leftsubmenu a:hover,
div.leftsubmenu a:active  { color:black; text-decoration:none; }
div.leftsubmenu a:hover   { background-color:lightyellow; }

a.leftsubmenu-head,
a.leftsubmenu-head-hilite {
	background-image:url(rtriangle.gif);
	background-position:right center;
	background-repeat:no-repeat;
	}
a.leftsubmenu-head-hilite { background-color:lightyellow; }
-->
</style>
Here is the HTML code used for the left menu.
<!-- Main Menu 1 -->
<div id="leftmenu" class="leftmenu" style="width:150px;">
<a href="javascript:submenu('leftsubmenu1')"
  class="leftsubmenu-head">Submenu</a>
<a href="javascript:submenu('leftsubmenu2')"
  class="leftsubmenu-head">Submenu 2</a>
<hr>
<a href="javascript:self.print()">Print</a>
<a href="javascript:self.close()">Exit</a>
</div>

<!-- Submenu Menu -->
<div id="leftsubmenu1" class="leftsubmenu" style="width:16ex;">
<a href="http://www.nowhere.com">Go Nowhere</a>
<a href="http://www.somewhere.com">Go Somewhere</a>
</div>

<!-- Submenu 2 Menu -->
<div id="leftsubmenu2" class="leftsubmenu" style="width:16ex;">
<a href="javascript:submenu('leftsubmenu3')"
  class="leftsubmenu-head">Submenu 3</a>
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>

<!-- Submenu 3 Menu -->
<div id="leftsubmenu3" class="leftsubmenu" style="width:12ex;">
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>
<script language="JavaScript" type="text/javascript">
  make_menu('rightmenu').SubmenuPosition='L';
</script>

The SubmenuPosition configuration option above places the submenus to the left of the menu as illustrated on the above menu to the right. It is explained below in the Configuration Variables section.

Here is the style sheet used for the right menu.
<style type="text/css">
<!--
/* Right Vertical Menus */
div.rightmenu,
div.rightsubmenu {
	background-color:#DDDDDD;
	border-width:1px;
	border-style:solid;
	border-color:black;
	text-align:right;
	padding:2px;
	}
div.rightmenu { position:relative; }
div.rightsubmenu {
	position:absolute;
	visibility:hidden;
	}

div.rightmenu a         { display:block; width:100%; }
div.rightmenu a:link,
div.rightmenu a:visited,
div.rightmenu a:hover,
div.rightmenu a:active  { color:black; text-decoration:none; }
div.rightmenu a:hover   { background-color:lightyellow; }

div.rightsubmenu a         { display:block; width:100%; }
div.rightsubmenu a:link,
div.rightsubmenu a:visited,
div.rightsubmenu a:hover,
div.rightsubmenu a:active  { color:black; text-decoration:none; }
div.rightsubmenu a:hover   { background-color:lightyellow; }

a.rightsubmenu-head,
a.rightsubmenu-head-hilite {
	background-image:url(ltriangle.gif);
	background-position:left center;
	background-repeat:no-repeat;
	}
a.rightsubmenu-head-hilite { background-color:lightyellow; }
-->
</style>
Here is the HTML code used for the right menu.
<!-- Main Menu 1 -->
<div id="rightmenu" class="rightmenu" style="width:150px;">
<a href="javascript:submenu('rightsubmenu1')"
  class="rightsubmenu-head">Submenu</a>
<a href="javascript:submenu('rightsubmenu2')"
  class="rightsubmenu-head">Submenu 2</a>
<hr>
<a href="javascript:self.print()">Print</a>
<a href="javascript:self.close()">Exit</a>
</div>

<!-- Submenu Menu -->
<div id="rightsubmenu1" class="rightsubmenu" style="width:16ex;">
<a href="http://www.nowhere.com">Go Nowhere</a>
<a href="http://www.somewhere.com">Go Somewhere</a>
</div>

<!-- Submenu 2 Menu -->
<div id="rightsubmenu2" class="rightsubmenu" style="width:16ex;">
<a href="javascript:submenu('rightsubmenu3')"
  class="rightsubmenu-head">Submenu 3</a>
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>

<!-- Submenu 3 Menu -->
<div id="rightsubmenu3" class="rightsubmenu" style="width:12ex;">
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>

Top

Push Up Menus

Menu1 Menu2 Menu3

The script to setup a menu that rises up from a menu bar is the same as that to setup a menu that drops down from a menu bar, with the addition of the MenuPosition configuration variable setting. The MenuPosition code and the SubmenuPosition code can be one of four settings: U (Up), D (Down), L (Left), or R (Right).

The above menus are setup by executing the following JavaScript:

<script language="JavaScript" type="text/javascript">
  initialize_menus();

  Menu.MenuPosition = "U";
  make_menu('upmenu1','upmenu_head1');
  make_menu('upmenu2','upmenu_head2');
  make_menu('upmenu3','upmenu_head3');
</script>

There is a bug that can be demonstrated with the above menus. First hover over all the Up Menus above. Next click on the link above them that says "Here is the style sheet used for the right menu.". You probably need to scroll down, but when you hover over the Up Menus again, you will notice that the pop up menus are not in the correct position.

Menu locations are saved once they are computed. If you change the inline position of the menus on the page, which is what happened when you clicked the above link, the saved menu locations are wrong. There are two solutions to this problem. The first, if you have program control of when the inline positions change, is to call the hide_menus(true) function with a sole argument set to true. That hides all menus and sets a flag to force their locations to be recomputed the next time they are displayed. The second solution is to set a configuration variable Menu.CacheLocation to false to force the computation of the menu locations each time they are displayed. See Configuration Variables below.

The stylesheet and the HTML code for Push Up Menus are the same as those used for the Drop Down Menus.

Here again is the style sheet used for these drop down menus.
<style type="text/css">
<!--
div.menu {
	visibility:hidden;
	position:absolute;
	color:black;
	background-color:lightyellow;
	border:solid black 1px;
	width:125px;
	}

div.menu a         { display:block; width:100%; }

div.menu a:link,
div.menu a:visited,
div.menu a:active,
div.menu a:hover   { color:black; text-decoration:none; }

div.menu a:hover   { background-color:lightgrey; }

a.menu-head,
a.menu-head:link,
a.menu-head:visited,
a.menu-head:hover,
a.menu-head:active,
a.menu-head-hilite,
a.menu-head-hilite:link,
a.menu-head-hilite:visited,
a.menu-head-hilite:active,
a.menu-head-hilite:hover {
	display:block;
	text-align:center;
	color:black;
	border:solid black 1px;
	width:75px;
	}

a.menu-head        { background-color:lightgrey; }

a.menu-head:hover,
a.menu-head-hilite { background-color:lightyellow; }
-->
</style>
Here is the HTML code used to define the above menu.
<!-- Up Menu Bar -->
<center>
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<a href="javascript:menu('upmenu1')"
  id="upmenu_head1" class="menu-head">Menu1</a>
</td>
<td>
<a href="javascript:menu('upmenu2')"
  id="upmenu_head2" class="menu-head">Menu2</a>
</td>
<td>
<a href="javascript:menu('upmenu3')"
  id="upmenu_head3" class="menu-head">Menu3</a>
</td>
</tr>
</table>
</center>

<!-- Main Menu 1 -->
<div id="upmenu1" class="menu">
<a href="javascript:submenu('upsubmenu3')">Submenu</a>
<a href="javascript:submenu('upsubmenu4')">Submenu 2</a>
<hr>
<a href="javascript:self.print()">Print</a>
<a href="javascript:self.close()">Exit</a>
</div>

<!-- Submenu Menu -->
<div id="upsubmenu3" class="menu">
<a href="http://www.nowhere.com">Go Nowhere</a>
<a href="http://www.somewhere.com">Go Somewhere</a>
</div>

<!-- Submenu 2 Menu -->
<div id="upsubmenu4" class="menu">
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>

Top

System Menus

File Edit View
New Open Save Save As
Print Setup Print
Properties Close
Cut Copy Paste
Select All
Find
Toolbars Status Bar Explorer Bar
Go To Stop Refresh
Text Size Encoding
Source Full Screen
Window
Message Post Contact
Standard Buttons Address Bar Links Radio
Customize
Search Favorites History Folders
Tip of the Day
Back Forward
Home Page
Largest Larger Medium Smaller Smallest
Auto-Select
Western European (Windows) Western European (ISO) More
Arabic (ASMO 708) Arabic (DOS) Arabic (ISO) Arabic (Windows)
Baltic (ISO) Baltic (Windows)
Central European (DOS) Central European (ISO) Central European (Windows)
Chinese Simplified
Chinese Traditional
Cyrillic (DOS) Cyrillic (ISO) Cyrillic (K018-R) Cyrillic (K018-U) Cyrillic (Windows)
Greek (ISO) Greek (Windows)
Hebrew
Japanese (Auto-Select) Japanese (EUC) Japanese (Shift-JIS)
Korean
Thai
Turkish (ISO) Turkish (Windows)
Unicode (UTF-8)
User Defined
Vietnamese

The above menus mimic the system menus found in Windows, Macintosh, and Linux. The buttons need to be clicked before activating the menus, but once activated, the menus stay open until the user selects an item or clicks away outside the menus.

This menu behavior is set up by defining the configuration variable Menu.ClickStart to be true.

This is the script used to set up the above menu bar.

<script language="JavaScript" type="text/javascript">
  initialize_menus();

  Menu.ClickStart = true;
  Menu.SubmenuOffsetX = -4;
  Menu.SubmenuOffsetY = 0;
  Menu.AllowReposition = false;
  make_menu('file','file_head');
  make_menu('edit','edit_head');
  make_menu('view','view_head');
</script>
Here is the style sheet used for the above menu.
<style type="text/css">
<!--
/* System Menu Styles */
.sysmenubar,
.sysmenubar td {
	font-family:Arial,Helvetica,sans-serif;
	font-size:8pt;
	color:black;
	}

.sysmenubar {
	padding:1px 1ex;
	background-color:#CCCCCC;
	border:outset #F0F0F0 2px;
	}

.sysmenubar a,
.sysmenubar a:visited,
.sysmenubar a:link,
.sysmenubar a:active,
.sysmenubar a:hover {
	color:black;
	text-decoration:none;
	cursor:default;
	}

.sysmenubar a.sysmenu-head,
.sysmenubar a.sysmenu-head-hilite {
	width:6ex;
	display:block;
	text-decoration:none; 
	text-align:center;
	}
.sysmenubar a.sysmenu-head        { border:solid #CCCCCC 2px; }
.sysmenubar a.sysmenu-head:hover  { border:outset #F0F0F0 2px; }
.sysmenubar a.sysmenu-head-hilite { border:inset #F0F0F0 2px; }

.sysmenu {
	position:absolute;
	visibility:hidden;
	font-family:Arial,Helvetica,sans-serif;
	font-size:8pt;
	background-color:#CCCCCC;
	border:outset #F0F0F0 2px;
	padding: 2px;
	}

.sysmenu a,
.sysmenu a:visited,
.sysmenu a:link,
.sysmenu a:active {
	display:block;
	width:100%;
	text-decoration:none; 
	color:black;
	}
.sysmenu a:hover {
	background-color:blue;
	color:white;
	}

.sysmenu a.syssubmenu-head {
	background-image:url(rtriangle.gif);
	background-position:right center;
	background-repeat:no-repeat;
	}

.sysmenu a.syssubmenu-head:hover,
.sysmenu a.syssubmenu-head-hilite,
.sysmenu a.syssubmenu-head-hilite:hover,
.sysmenu a.syssubmenu-head-hilite:visited {
	color:white;
	background-color:blue;
	background-image:url(rtriangle_white.gif);
	background-position:right center;
	background-repeat:no-repeat;
	}
-->
</style>
Here is the HTML code defining the menu bar and the first menu.
<!-- Menu Bar -->
<div class="sysmenubar">
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<a href="javascript:menu('file')"
  id="file_head" class="sysmenu-head">File</a>
</td>
<td>
<a href="javascript:menu('edit')"
  id="edit_head" class="sysmenu-head">Edit</a>
</td>
<td>
<a href="javascript:menu('view')"
  id="view_head" class="sysmenu-head">View</a>
</td>
</tr>
</table>

<!-- File Menu -->
<div id="file" class="sysmenu" style="width:22ex;">
<a href="javascript:submenu('new')" class="syssubmenu-head">New</a>
<a href="javascript:self.open()">Open</a>
<a href="#">Save</a>
<a href="#">Save As</a>
<hr>
<a href="#">Print Setup</a>
<a href="javascript:self.print()">Print</a>
<hr>
<a href="#">Properties</a>
<a href="javascript:self.close()">Close</a>
</div>

<!-- New Submenu -->
<div id="new" class="sysmenu" style="width:18ex;">
<a href="javascript:self.open()">Window</a>
<hr>
<a href="#">Message</a>
<a href="#">Post</a>
<a href="#">Contact</a>
</div>

A minor variation of the above menus can be obtained by setting the configuration variable Menu.ClickStop to true instead of Menu.ClickStart. That causes the menus to automatically drop down without clicking the mouse, but the user must click the mouse to hide the menus — either by clicking on a menu selection or by clicking somewhere outside of the menus. Setting Menu.ClickStart to true automatically sets Menu.ClickStop to true, but setting Menu.ClickStop to true does not automatically set Menu.ClickStart to true.

Top

Fixed Menus

Menu 2

M
e
n
u
1
 
Menu 1
Cool stuff
Menu 2
Cool stuff Cool stuff
Menu 3
Cool stuff Cool stuff Cool stuff

M
e
n
u
3

The above menus are referred to as "fixed" menus because the menus are always displayed in a fixed location. The three menus above just happen to be all located at the same coordinate.

These menus are set up by setting the configuration variable Menu.MenuFixed to "true" to prevent the software from positioning the menus to be next to their headers. The menus are instead placed according to their CSS top and left style settings. Setting Menu.SubmenuFixed to "true" prevents submenus from being positioned too.

The above menus also demonstrate the Menu.KeepOpen configuration setting, which keeps the menu displayed even if the user clicks away on another part of the page. It is more tenacious than the Menu.ClickStop setting described above.

These menus are setup with the following JavaScript. The last line of the script shows how to automatically display a menu when a page loads.

<script language="JavaScript" type="text/javascript">
  initialize_menus();

  Menu.MenuFixed = true;
  Menu.KeepOpen = true;
  make_menu('fixedmenu1','fixedmenu_head1');
  make_menu('fixedmenu2','fixedmenu_head2');
  make_menu('fixedmenu3','fixedmenu_head3').show_menu();
</script>
Here is the style sheet used for the above menu.
<style type="text/css">
<!--
/* Fixed Menu Styles */
.fixedmenu {
	position:absolute;
	visibility:hidden;
	background-color:lightyellow;
	border:outset #F0F0F0 2px;
	padding: 2px;
	}
a.fixedmenu-head,
a.fixedmenu-head:link,
a.fixedmenu-head:visited,
a.fixedmenu-head:hover,
a.fixedmenu-head:active,
a.fixedmenu-head-hilite,
a.fixedmenu-head-hilite:link,
a.fixedmenu-head-hilite:visited,
a.fixedmenu-head-hilite:active,
a.fixedmenu-head-hilite:hover {
	display:block;
	text-align:center;
	color:black;
	border:outset #F0F0F0 2px;
	width:75px;
	}
a.fixedmenu-head
	{ background-color:lightgrey; color:black; }
a.fixedmenu-head:hover,
a.fixedmenu-head-hilite
	{ background-color:lightyellow; color:black; }
-->
</style>
Here is the HTML code used to define the above menu.
<table cellspacing="0" cellpadding="5" border="0">
<tr height="26">
<td width="26"></td>
<td width="208" align="center" valign="middle">
<a href="javascript:menu('fixedmenu2','fixedmenu_head2')"
  id="fixedmenu_head2" class="fixedmenu-head"
  style="width:200px;height:24px;">Menu 2</a>
</td>
<td width="26"></td>
</tr>
<tr height="210">
<td width="26" align="center" valign="middle">
<a href="javascript:menu('fixedmenu1','fixedmenu_head1')"
  id="fixedmenu_head1" class="fixedmenu-head"
  style="width:24px;height:200px;">
<br>M
<br>e
<br>n
<br>u
<br>1
<br></a>
</td>
<td width="208" align="center"><div style="position:relative">

<!-- Spacer -->
<div style="width:202px;height:202px"> </div>

<!-- Fixed Menus -->
<div id="fixedmenu1" class="fixedmenu">
<center>
<font size="24pt">Menu 1</font><br>
<img src="star.gif" border="0" alt="Cool stuff">
</center>
</div>

<div id="fixedmenu2" class="fixedmenu">
<center>
<font size="24pt">Menu 2</font><br>
<img src="star.gif" border="0" alt="Cool stuff">
<img src="star.gif" border="0" alt="Cool stuff">
</center>
</div>

<div id="fixedmenu3" class="fixedmenu">
<center>
<font size="24pt">Menu 3</font><br>
<img src="star.gif" border="0" alt="Cool stuff">
<img src="star.gif" border="0" alt="Cool stuff">
<img src="star.gif" border="0" alt="Cool stuff">
</center>
</div>


</div></td>
<td width="26" align="center" valign="middle">
<a href="javascript:menu('fixedmenu3','fixedmenu_head3')"
  id="fixedmenu_head3" class="fixedmenu-head"
  style="width:24px;height:200px;">
<br>M
<br>e
<br>n
<br>u
<br>3
<br></a>
</td>
</tr>
</table>

Fixed menus can be used in situations that are not traditionally thought of as a use for menus. Entire sections of html can pop in and out as the mouse hovers over buttons. They turn AcmeMenu into a tool that can be used to design a persistent interface — an interface where the controls are static and the information moves in an out.

Top

Mack Menus

Menu1 Menu2 Menu3

Form

First
Second
Third
Check One Two

I didn't know what to call this style of menu, its not really that distinct of a style. It is my favorite. These menus are a combination of the normal HTML drop-down menus and the System menus. The menus pop open as soon as the mouse hovers over them, but the menus remain displayed as if the Menu.ClickStop variable was set, except that if the user doesn't click within a specified length of time, the menus automatically close. Simply put, the menus stay open for a set amount of time after the mouse wanders outside their borders. Setting the delay time to about a half of a second gives a nice lazy feel to the menus, and helps ease the wear and tear on my poor worn out hands.

The above menus are setup by executing the following JavaScript:

<script language="JavaScript" type="text/javascript">
  initialize_menus();

  Menu.HideDelayTime = .5;	// seconds
  make_menu('mackmenu1','mackmenu_head1');
  make_menu('mackmenu2','mackmenu_head2');
  make_menu('mackmenu3','mackmenu_head3');
</script>

The stylesheet and the HTML code for Mack Menus are the same as those used for the Drop Down Menus.

Here again is the style sheet used for these drop down menus.
<style type="text/css">
<!--
div.menu {
	visibility:hidden;
	position:absolute;
	color:black;
	background-color:lightyellow;
	border:solid black 1px;
	width:125px;
	}

div.menu a         { display:block; width:100%; }

div.menu a:link,
div.menu a:visited,
div.menu a:active,
div.menu a:hover   { color:black; text-decoration:none; }

div.menu a:hover   { background-color:lightgrey; }

a.menu-head,
a.menu-head:link,
a.menu-head:visited,
a.menu-head:hover,
a.menu-head:active,
a.menu-head-hilite,
a.menu-head-hilite:link,
a.menu-head-hilite:visited,
a.menu-head-hilite:active,
a.menu-head-hilite:hover {
	display:block;
	text-align:center;
	color:black;
	border:solid black 1px;
	width:75px;
	}

a.menu-head        { background-color:lightgrey; }

a.menu-head:hover,
a.menu-head-hilite { background-color:lightyellow; }
-->
</style>
Here is the HTML code used to define the above menu.
<!-- Menu Bar -->
<center>
<table cellspacing="0" cellpadding="0">
<tr>
<td>
<a href="javascript:menu('mackmenu1')"
 id="mackmenu_head1" class="menu-head">Menu1</a>
</td>
<td>
<a href="javascript:menu('mackmenu2')"
 id="mackmenu_head2" class="menu-head">Menu2</a>
</td>
<td>
<a href="javascript:menu('mackmenu3')"
 id="mackmenu_head3" class="menu-head">Menu3</a>
</td>
</tr>
</table>
</center>

<!-- Main Menu 1 -->
<div id="mackmenu1" class="menu">
<a href="javascript:submenu('macksubmenu3')">Submenu</a>
<a href="javascript:submenu('macksubmenu4')">Submenu 2</a>
<hr>
<a href="javascript:submenu('mackformmenu2')">Form<img
 src="star.gif" border="0" alt="Cool stuff"></a>
<hr>
<a href="javascript:self.print()">Print</a>
<a href="javascript:self.close()">Exit</a>
</div>

<!-- Submenu Menu -->
<div id="macksubmenu3" class="menu">
<a href="http://www.nowhere.com">Go Nowhere</a>
<a href="http://www.somewhere.com">Go Somewhere</a>
</div>

<!-- Submenu 2 Menu -->
<div id="macksubmenu4" class="menu">
<a href="javascript:submenu('macksubmenu41')">Submenu 3</a>
<a href="http://www.north.com">Go North</a>
<a href="http://www.south.com">Go South</a>
<a href="http://www.east.com">Go East</a>
<a href="http://www.west.com">Go West</a>
</div>

Top

Configuration Variables

As seen above, the actions of a menu can be altered by configuration variables. They can be set globally before making menus with make_menu(), or they can be set afterwards for an individual menu by using the object returned by make_menu(). For example:

Menu.SubmenuOffsetX = 0;  // Set globally for all menus

var m1 = make_menu('menu_id1','menu_header_id1');
var m2 = make_menu('menu_id2','menu_header_id2');

m1.SubmenuOffsetY = 0;    // Set individual menu

The values assigned to the configuration variables below are the default values initially set to the variables in the software.

The following offset constants are used to position the menu or submenu relative to their header elements. Menu panels are positioned from the lower left corner of the header. Submenu panels are positioned from the upper right corner of their header.

Menu.MenuOffsetX = 0;		// Offset from left side of menu header
Menu.MenuOffsetY = 0;		// Offset from bottom of menu header
Menu.SubmenuOffsetX = 0;	// Offset from right side of submenu header
Menu.SubmenuOffsetY = 0;	// Offset from top of submenu header

Border dimensions and padding around menus and their headers need to be known for accurate placement of the menus. The dimensions are read from the element's style attribute or they are read from the CSS stylesheet settings. The units of measure must be pixel units (px) in order to be correctly interpreted. Other measurements such as ex, em, in, and cm are not converted.

If style settings cannot be read, the following constants are used.

Menu.MenuHeaderBorderWidth = null;
Menu.MenuHeaderPadding = null;
Menu.MenuHeaderPaddingHorz = null;
Menu.MenuHeaderPaddingVert = null;

Menu.MenuBorderWidth = null;
Menu.MenuPadding = null;
Menu.MenuPaddingHorz = null;
Menu.MenuPaddingVert = null;

Menu.SubenuHeaderBorderWidth = null;
Menu.SubenuHeaderPadding = null;
Menu.SubenuHeaderPaddingHorz = null;
Menu.SubenuHeaderPaddingVert = null;

Menu.SubmenuBorderWidth = null;
Menu.SubmenuPadding = null;
Menu.SubmenuPaddingHorz = null;
Menu.SubmenuPaddingVert = null;

Menus can be set to be dormant until the menu header is clicked. This activates a behavior similar to system menus.

Menu.ClickStart = false;

Menus can be set to stay open until a mouse click. If ClickStart is true, then ClickStop is also forced to be true.

Menu.ClickStop = false;

Menus can be set to stay open, even after a mouse click. The menus remain displayed until another menu that has the KeepOpen flag needs to be shown.

Menu.KeepOpen = false;

Menus can be set to stay open a set number of seconds after the mouse wanders outside them. It is like the ClickStop flag being set with an click event automatically scheduled to occur after the specified number of seconds.

Menu.HideDelayTime = 0;

Menus can be "frozen" open if the mouse is clicked inside them. Set AllowFreeze to "false" to turn off that feature.

Menu.AllowFreeze = true;

Menus and submenus can project out in different directions from their header. By default, menus pop "Down", and submenus pop "Right". The position codes can be set to one of the following constants:
U (up), D (down), L (left), or R (right).

Menu.MenuPosition    = "D";
Menu.SubmenuPosition = "R";

The edges of the menus and submenus are aligned to the MenuPosition or SubmenuPosition. By default, menus are aligned using to their left edge and submenus are aligned on their top edge. The alignment codes can be set to one of the following constants:
T (top), B (bottom), L (left), or R (right).

Menu.MenuAlign = "L"; 
Menu.SubmenuAlign = "T";

Menus are usually repositioned if necessary to keep them within view. Set AllowReposition variable to "false" to turn off that feature.

Menu.AllowReposition = true;

Menus can be classified as vertical menus (the default), horizontal menus, or neither. The classification are only hints used for the placement of submenus. Menus are place relative to their header's dimensions, but submenu coordinates are adjusted slightly so that their menu items line up directly across from each other or up and down vertically. If a menu is neither vertical or horizontal, the extra adjustments are not made so that submenus line up with their headers just like menus line up with their headers. The MenuOrientation and SubmenuOrientation variables can be set to one of the following constants:
V (vertical), H (horizontal), or N (neither).

Menu.MenuOrientation    = "V";
Menu.SubmenuOrientation = "V";

Menu locations are cached once they are computed. However, if the inline position of the menus changes, the cached coordinates become invalid. There are two methods to deal with this problem. The first is to set the CacheLocation to false to force the menu's coordinates to be computed each time they are shown. The second method is to invoke the hide_menus(true) function with its argument set to true to hide the menus and to force their location to be recomputed the next time they are shown.

Menu.CacheLocation = true;

Menus can be fixed at a predetermined location by setting the CSS styles left and top, and by setting the Menu.MenuFixed configuration constant to true. The same is true for submenus, their location is fixed on the page if Menu.SubmenuFixed is true.

Menu.MenuFixed = false;
Menu.SubmenuFixed = false;

The menu z-index is used to ensure that menus are displayed on top of the document. The submenu z-indexes are automatically incremented to be greater than their parent's menu z-index.

Menu.ZIndex = 1000;

The highlight suffix is appended to a menu header's class name -- if it has one. This allows the selected path to stay highlighted as the mouse moves over the submenu.

Menu.HighlightSuffix = "-hilite";

Functions assigned to OnShowMenu and OnHideMenu are triggered whenever a menu is displayed or hidden. The menu object is passed to the functions as their sole argument. These functions are good for hiding elements that insist on being displayed on top of everything, including the menus. Troublesome elements are the <select> tags in Internet Explorer on Windows and the <iframe> elements on the Macintosh Safari and Internet Explorer.

Menu.OnShowMenu = null;
Menu.OnHideMenu = null;

Timing delays are used before actually showing or hiding a menu. Increase these numbers if menus items have large padding. The mouse needs to go from a submenu header across the padding onto the submenu within the TimeToHide time to ensure smooth operation. The measurements are in milliseconds.

Menu.TimeToShow = 150;
Menu.TimeToHide = 100;
Top Top

Suggestions

The following are suggestions to use to set up menus. They are not necessarily "good programming practices", rather they are tricks that make the menus work across the broadest range of browsers.

Version 6 browsers, those which implement the DOM 1 and most of the DOM 2 standards, work well with the menus. External CSS stylesheets can be used for all display characteristics and the calculation of menu locations is accurate. Accommodating Version 5 browsers is a bit trickier.

Top

Basic Suggestions

Top

Internet Explorer 5 Suggestions

Top

Internet Explorer 5 for Macintosh Suggestions

Top

Netscape 6.0 and Mozilla 1.0 Suggestions

Top

Opera 7 Suggestions

Top

Opera 6 Suggestions

Top

Opera 5 Suggestions

Top

Testing Menus

Menus can be tested on any page by loading the source code file and turning on the debug mode. That is done by copying the following statement into your document between the <head> and </head> tags.

<script src="AcmeMenu_source.js" type="text/javascript"></script>

After the page is displayed, type the following into the browser's address bar:

javascript:debug.on()

Turning on the debug mode opens up a second window showing a trace of all the browser events handled by the software and the progression it used to determine the coordinates of the menus. To turn off the debug mode, close the debug window or type the following into the address bar:

javascript:debug.off()

There is a separate test page for menus located at testmenu.htm which is included in the AcmeMenu.zip download file. It has several menus to exercise the software and to test the placement of the menu panels in different situations. It has buttons for turning the debug mode on and off.

Top