Pop Goes the Menu

Pop Goes the Menu

HTML pop-up menus are becoming more common in Web applications because they expand the available screen area by placing destination links in an invisible but easily accessed location. However, the process for creating these menus is not as simple as building a list of links. Until recently, you couldn’t build a single code base to display pop-up menus in both major browsers; but now that Netscape 6 (NS6) and Internet Explorer 5 (IE5) share much of the same object model, designing and implementing a menu system is easier than ever before.

The Pop-Up Menu Procedure
Heres the procedure:

   1. Create a menu bar across the top of the page
   2. Populate the menu bar with some menu triggers
   3. Position the menus themselves directly beneath the appropriate triggers
   4. Center the triggers on the screen

That sounds simple enough! Start by creating three style sheet rules: one for the menu bar, one for the menu triggers, and one for the menus themselves. The following style tag includes basic hyperlink rules for the links embedded in the menus:


While some of these properties are redundant and could have been combined, I find it easier to read the code when they’re entered separately. Note that the height, padding, and top properties for the triggers are identical to those for the menu bars. The top property for the menu rule is equal to the height of the triggers plus twice the padding (top and bottom). Also, note that the menu bar is the only element with a left property; you’ll set the left properties for the triggers and menus at run time.

Finally, look at the cursor properties for the menuTrigger rule. There are two cursor properties, one for each browser type. The first one, cursor: pointer, forces NS6 to use a hand-shaped cursor. The second, cursor: hand, does the same thing for IE5. Thankfully, each browser ignores the setting it doesn’t understand. The dual property setting replaces the default plain text I-beam cursor with the hand cursor, and lets you avoid wrapping the triggers in elements to change the cursor by trapping mouse events.

Build the Menu System
Its time to build the menu system. This example creates four menus with associated triggers, but the procedure works identically with any number of menus


Write the Code
Now you can write some code. Menu systems really only do three things:

   1. Show the appropriate menu when the mouse enters a trigger
   2. Hide any other menu
   3. Keep track of which menu is currently visible

One way to translate the preceding pseudo-code into JavaScript is:

   var mnuSelected = ”;   function showMenu(menu){   hideMenu(mnuSelected);   document.getElementById(menu).style.visibility = ‘visible’;   mnuSelected = menu;   }   function hideMenu(menu){   if(mnuSelected!=”)      document.getElementById(menu).style.visibility = ‘hidden’;   }
The mnuSelected variable keeps track of the current menu while the two functions show or hide the respective menu. That was pretty simple! The only thing left to do in code is the positioning.

To center things on the screen youll need the available width of the window. Unfortunately, IE5 and NS6 do this differently so youll have to fork the logic. IE5 uses the proprietary document.body.clientWidth while NS6 uses the W3C standard innerWidth property of the window object. Since IE5 uses a property of the document, youll have to wait until the document is loaded before gaining access to it. That also means that youll have to wait until the document loads before positioning the menus. The onLoad event of the element triggers an init function that performs the positioning tasks:

   function init(){   if(document.all){      aWidth = document.body.clientWidth;      document.getElementById(‘menuBar’).style.width = aWidth;   }else{      aWidth = innerWidth;      document.getElementById(‘menuBar’).style.width = aWidth-8;   }   document.getElementById(‘About’).style.left = parseInt((aWidth/2 – 200));   document.getElementById(‘Services’).style.left = parseInt((aWidth/2 – 100));   document.getElementById(‘Samples’).style.left = parseInt(aWidth/2);   document.getElementById(‘Contact’).style.left = parseInt((aWidth/2 + 100));   document.getElementById(‘mnuAbout’).style.left =       document.getElementById(‘About’).style.left;   document.getElementById(‘mnuServices’).style.left =       document.getElementById(‘Services’).style.left;   document.getElementById(‘mnuSamples’).style.left =       document.getElementById(‘Samples’).style.left;   document.getElementById(‘mnuContact’).style.left =       document.getElementById(‘Contact’).style.left;   }
The if(document.all) test differentiates between IE5 and NS6. The expression evaluates to true for IE5 but fails for NS6. Notice that the code sets the width of the menuBar element differently depending on the browser type. In my informal testing, NS6 will include that annoying side bars border in the value returned for innerWidth. Interestingly, it doesnt matter what size a user makes the side bar, as that area is not included in the innerWidth property value. In any event, if you dont subtract out a few pixels youll get a horizontal scroll bar across the bottom of the page. On my system, eight pixels seemed to be the magic number.

Also notice that I hard coded the positions of the menu triggers; however to make the code more generic, you could create a variable for the number of menus and get the left values based on the particular menu and its position in the queue. For this simple example though, I wanted the code to be as readable as I could make it.

Attach the Events
The last thing to do is to attach the events. Here is the modified About menu trigger:


And here is the associated About menu:



Share the Post: