devxlogo

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:

   

I included both mouse over and mouse out events for each menu as NS6 fires a mouse out event during the transition from the trigger to the menu.

The final touch is to modify the menu items so that they highlight when the mouse passes over them. One possible solution is to modify each item in the menu so that it looks like this:

   

About 1

Once again I wrapped the text in an element but I assume that each menu item will have some function to perform. You can replace the # with an appropriate call.

To make the system work, modify the element so that it calls init(). Ive also included an onResize event so that the window will reposition the menus and resize the menu bar whenever the user resizes the window:

   

Add Sub-Menus
Adding sub-menus to the system is almost as intuitive as implementing the main menus. To illustrate, Ill add a sub-menu to the first mnuAbout menu item. Start by declaring the menu inside a

element:

   

Set the top of the sub-menu to 30 pixels. Since the item that triggers the sub-menu is a

element, not a

, and it has no positioning style rules, I arrived at the number through trial and error. The number 30 seemed to work best for both IE5 and NS6. From a readability standpoint, this seemed a simpler approach than setting each menu item in a

and positioning it dynamically. Its imperfect but it works.

Now, add two functions and a variable to keep track of the currently visible sub-menu:

   var subMnuSelected = ”;   function showSubMenu(menu){   hideSubMenu(subMnuSelected);   document.getElementById(menu).style.visibility = ‘visible’;   subMnuSelected = menu;   }   function hideSubMenu(menu){   if(subMnuSelected!=”)      document.getElementById(menu).style.visibility = ‘hidden’;   }
These functions are nearly identical to those for the main menu system but they have a separate index because the menu that triggers the sub-menu should stay visible while the sub-menu is visible. Using the functions for the main system would hide the trigger menu while showing the sub-menu.

To set the sub-menus left property, add this code to the end of the init() function:

   document.getElementById(‘mnuAboutSub1’).style.left =    parseInt(document.getElementById(‘About’).style.left) + 100;
Now its time to attach the events. Youll have to modify the main menu triggers like this:

   

Next, modify the mnuAbout

so that it hides any sub-menu in the onMouseOut event:

   

Finally, modify the About 1

element to show the sub-menu:

   

About 1

The only code of interest here is the call to event.cancelBubble. Without canceling the event in the

element, IE5 will propagate the event to the parent

where hideSubMenu() is called. The result would be that the sub-menu would become visible and then immediately disappear. Thats not very user friendly!

With a little work, this simple menu system can do many things. For example, you have the ability to place your menus wherever youd like. I used a horizontal menu bar but implementing a vertical bar shouldnt be all that difficult. Just match the top property of the menus to the triggers instead of the left when positioning. This is what DHTML is supposed to be like: a unified object model, an intuitive design process, and no bloated graphics. Its getting to be fun again!

See also  Custom Java Web Development - The Heartbeat of Modern Web Development
devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist