MENUS AND BUTTONS Part II
The Six Button and Menu Files
atest-buttons-and-menu-tests.html is 17.4K. As already covered, it tests menus and buttons and reveals a lot about the underrated onMouseMove and overrated onMouseOut event handlers. The original file (popups on top and rollover buttons on the top and side) was created in Cool Page, the WYSIWYG web page editor; it was over 30K, was slower in operation, and used many functions. But Cool Page was careful to work in all browsers from version 4 on—even weirder ones, while we've decided that the dastardly days of dino dabbling are done for us so our files work in W3C DOM-compatible browsers only. Even with all the code it took for us to experiment with eight different types of button operations and support IE 5+ and Netscape 6+ and the other W3C DOM-compatible browsers, loading and memory use (both page memory and file size) as well as performance were better in the 17K atest-buttons-and-menu-tests.html file than the Cool Page file, even though it used only the replace type of button operation.
atest2-buttons-are-bkgr-change-divs.html is 12K. This file tests the use of background color changing in the div for all 16 buttons. We cleaned up the code by tossing all unnecessary table code and font code, 86ing the unneeded functions, deleting the excess browser sniffing code, as well as dumping all use of images for buttons—all of which Cool Page v2.72 had added. Sixteen colored divs suffice just fine. You’ve already seen the relevant codes for this above. For the popups, the popup menu image upon which a text box is superimposed is still the main plan here—just like in the above button-testing file.
atest3-no-images-top-menus.html is 10.4K. This file uses no popup menu image upon which a text box is superimposed—it just colors the text box and forgets about an image backdrop. So, even though the fetching of hidden text boxes still happens, no images are needed anywhere. (The two navbar images and the blue gradient header bar are all superfluous—they have only aesthetic function.) Instead of images behind div text, we simply colored the div itself with a background color and added a div border. Netscape gets the prize for having more dynamic support for thin borders than IE 5.5. A 2-pixel-wide groove border style gives only a plain border in IE 5.5, but a fancy one in Netscape, although both browsers do the various border styles well if the border widths are substantial.
We had to deal with narrowing the popup width due to Netscape’s (and the W3C’s) quirks again (and once again the event capturing routine isn't related to this issue—it’s just a convenient place to do the fix). We’re aware that the conventional wisdom is that IE should be seen as the one with the quirks here, not Netscape, but we aren't that wild about much of the conventional wisdom in this world and this is but one example. See below and don’t focus on the for loop. Note instead the need for reducing an 87px-wide box to an 83px one due to the 2px border being (correctly) put around the box by NN nerds rather than inside the box (which we think is great) by the IEnsteins. Note also syntax fussiness when concatenating a value for t which handles id’s from id811 to id881 adding 10 for increments, and the ease with which any number of elements with sequentially numbered id’s can have their style properties adjusted with hardly any code overhead:
function startmouse() {if(Netscape) {document.captureEvents(Event.MOUSEMOVE);
for(var i=1;i<9;i++){t='id8' + i + '1'; document.getElementById(t).style.width=83;}}
atest4-no-images-side-menus.html is 10.8K. This file does the same as the previous one except the popups are on the side and the buttons with links are on the top. Below is the popup erasing routine. It’s more complicated than the one for the top popups because we’re not just dealing with detecting mouse exits within a rectangle which includes button and popup. The relevant code below is stating: Let’s dump the popup when the mouse is outside the button and left of the right border of said button AND when the mouse is outside the popup and right of the right border of the button. Go look at the side popup action now for yourself and notice where the buttons and popups are on the screen. Read the previous sentence again and you'll see why side popups take more code than top popups. There were no parameter checks analogous to &&x<109 or &&x>108 with top popups.
if(p>0&&f>0){
if((y<(206+(p-1)*29))||(y>(235+(p-1)*29)&&x<109)||(y>(318+(p-1)*29)&&x>108)||x<37||x>236){ (dump popup)
But let’s go through this file’s code in more detail:
The style section at the beginning says no link underlines, then it gives the popup text background colors and text colors that look nice and like the "buttons" on the popup box image get pushed. Next all 16 button links get their link background color area sized to the button size and the color is made transparent, so the link background color from "all" text links (which we applied only to the 48 popup text links) doesn’t get applied. Next the style rules (applied to all buttons) in class .b are that the text must be aligned center, it must be a certain size and with a certain background color, and it must be a certain font size, style, and family. Finally, the .h class rules specify the popup boxes’ size, color, hiding place behind the blue side panel when not in use, and border width, style, and color.
Next, global variables are stated and an abbreviated browser sniffer detects whether Bill’s Boys or the NN nerds are the ones to blame for the users’ browser. Next, the Netscape variable leads the code to beginning event capturing—which IE need not do. Next, the startmouse code document.onmousemove=getCoords; sets the onMouseMove handler for the document to be the function getCoords(). This means that the onMouseMove event handler is going all the time from now on.
Then comes the getCoords() function and its x-y coordinate reading. Then there's the popup eraser already discussed. Immediately afterwards there's:
stringum();
box(i2,4,444);
p=0;f=0;
}
}
else if(x>37&&x<109&&y>206&&y<438&&f==0){
f=1;p=parseInt((y-177)/29);
stringum();
box(i2,147,i5);
}
}
function stringum(){i2='id' + ( 801 + (p*10)).toString();i5=206+(p-1)*29;}
The purpose of stringum() is determining the correct popup id and the correct y coordinate value for placing the popup, according to mouse position and p value. The box function moves the popup to hide under the blue side panel. The else-if conditional pops a popup if the mouse is on one of the side buttons and no other popup is popped (f==0). The decimal p value (which popup) is determined and the built-in parseInt() function converts that to an integer. The f flag (a popup is popped) is set and stringum again gets needed popup moving values. The box function now displays the popup—in its popup position—next to the side panel and across from its button. Here's the box() function:
function box( q, s, u ) {var e=document.getElementById(q); if(s>=0)e.style.left=s+'px';if(u>=0)e.style.top=u+'px';}
It’s looking for the box id q, and x and y coordinates (s and u) of the div to place.
Next the browser sniffer finds out if the user’s browser is W3C DOM capable with if(!document.getElementById) and gently suggests that the web page won't run in their browser so they should update. Note that throughout our code, we leave out various codes that dabble with dinos, but also some codes that keep old browsers away from what they cannot comprehend, as well as alternate text code for disabled or graphics-hating user’s use or just simply for browsers with images turned off for efficiency. We expect programmers to deal with these issues in their own way. We support such things. Even code for NN4—it’s fine with us if programmers wish to add such things. It’s just that we’re doing our best to get users to move on—as 96+ percent have—out of the dino dabbling dark ages, and we do this for the good of all.
Next there's the onLoad="startmouse()" in the body tag to get onMouseMove off to the races, then the text testing div, which we styled only with the BODY {margin-left:0; margin-right:0; margin-top:0; font:normal 13px Arial, sans-serif;} rule in the CSS styles at the start of our code. If we were going to have more paragraphs and other content, we’d use a more dynamic style sheet approach, of course.
After that comes the header div, then lines made from colored divs or border placed in divs. Then there's the top section of the two-part side panel. There's a section of side bar below this one that hides the popups under it so its z-index is high—which in turn was accomplished by having it be the last div in the code. The last objects on a page get the highest z-indexes and the first ones get the lowest. Since a loading HTML page parses from top to bottom in displaying contents, obviously the lowest layer (which corresponds to the first items after the body tag), the one beneath all others, gets loaded first. The top section of side bar must go beneath a navbar and eight buttons, so it is declared as the seventh div on the page to keep it under the buttons and navbar which we put in sequentially later.
Then come the eight top navbar button divs, which are styled by class b except for the left CSS style property, which is unique to each of these divs. The side navbar div is next and the eight button divs that are in it come after that, so they’ll be on—not under—the navbar. Unique here is each button’s top property. Next come the eight popup divs and the second half of the blue side bar. The former have class h style rules covering their hideaway coordinates, size, color, and border.
And that’s all it take to make a dynamite set of buttons and popups with low code and memory requirements. We hope we haven't "spoiled" you by sending such neat stuff your way, and we hope your sense of humor survived our liberties, cheap shots, and satire. And, above all, smile! George Bush has—as they say on JAG—got your six!
atest5-animated-and-misc-buttons.html is 13.7K. This is an experimental file, created to test animated gifs’ role in buttons. We’ll get to the details momentarily.
This file does the same as the previous one including the fact that the popups are on the side and the buttons with links are on the top. We haven't mentioned yet that for most of our files—including this one—we've used the cursor:default CSS styling technique to keep the cursor an arrow rather than a text cursor when the mouse is over buttons with text but no link. Text cursors look bad on buttons. Now, the experiments:
We created eight different animated gifs in the Pro version of ImageForge ($28) for the top buttons, and one extra animated gif for the side buttons—all eight side buttons use the same gif. To make the gifs, just select New and when you see the dialogue box check animated gif on the check box. Use the standard drawing tools to make a button. Once you’ve got one frame done, click the blue circle icon to duplicate the frame and add a new frame to the end of the sequence concomitantly. Before you press Ctrl a to "save as," make sure you’ve checked the defaults under the Set Preferences item on the Options menu. The Saving tab has a place to enter 0 to represent the choice that your animations will loop forever. Of course, if you'd rather set a finite number, that’s fine too. If you make a bunch of animated gifs and wish to change the number of repeats, it’s faster to go to the FREE Microsoft GIF Animator, load in a gif, and set the repeats on the Animation tab. It’s also a good place to change frame timing on the Image tab or click on frames and drag them to different places in the sequence of thumbnail images in order to change sequence order.
After starting with the file atest4-no-images-side-menus.html, we used the animated buttons to replace colored div box buttons for the top buttons, then we edited the file in other ways. We added a text box layer underneath (lower z index, so put it in the HTML code before the gifs) animation gifs with crisp words or phrases done in red. Then we used the slowopacity() function so as to have the onMouseOver’ed button—still animating—slowly disappear and reveal the witty words lying beneath. Once your mouse exits, the button will slowly appear again:
<DIV style="left:149px;" class="u"><p>(please)</p></DIV>
<DIV><A HREF="t.html"><IMG SRC="anim1.gif" ID="id91Img" border=0 style="position:absolute; top:117px; left:149px; width:72px; height:28px; filter:alpha(opacity=100);-moz-opacity:1.0;" onMouseOver="if(sl==0&&k==0){
sl=1;g='id91Img';javascript:slowopacity(100);return true}"></A></DIV>
Here's the class styling for the div with witty words:
.u {position:absolute; top:117px; width:72px; height:28px; text-align:center; vertical-align:center; font:bold 11px Tahoma, sans-serif; color:red;}
Here's the way we catch the mouse exiting the button it was in. The sl flag being set (=1) means the mouse is on a top "slow" button. The k flag being set (=1) means the slow opacity effect is completed (the gif has vanished). The k flag equaling 0 means the undoing of the opacity effect is completed so the gif is 100% visible. The k flag is needed because one can move the mouse over a different button before the vanishing or reappearing effects are completed, which cause bugs in its functionality without the k flag.
if(sl==1&&k==1){p=parseInt((x-69)/73);if((x<(149+(p-1)*73))||(x>(222+(p-1)*73))||y<117||y>145)
{sl=0;slowopacity(0);}}
Note the setting and unsetting of the k flag below:
function slowopacity(o) {
if (sl==0){
if (o < 100) {
o = o + 10;
opacity(g,o);
setTimeout("slowopacity(" + o + ")", 100);if(o==100)k=0;
}
}
else{
if (o > 0) {
o = o - 10;
opacity(g,o);
setTimeout("slowopacity(" + o + ")", 100);if(o==0)k=1;
}
}
}
Here's how we put animated gifs underneath colored (background-color) divs. The side buttons are all this way. When the mouse is on the button, the top div vanishes and shows the gif.
<DIV style="position:absolute; top:206px; left:37px; width:72px; height:28px;"><IMG SRC="anim9.gif" WIDTH=72 HEIGHT=28 BORDER=0></DIV>
<DIV ID="id51" style="top:206px; left:37px;" class="b" onMouseOver="javascript:backgrnd('id51',1);return true" onMouseOut="javascript:backgrnd('id51',0);return true">back-<br>ground</a></DIV>
Here's the background function. In the last file, it was to change the dark blue to light blue in the colored div button. Here it changes the side buttons from dark blue to transparent so the animated gif underneath is seen.
function backgrnd( t, r ) {c='transparent';if(!r)c='#0482fc'; document.getElementById(t).style.backgroundColor = c;}
The result of our experiment was something that worked on both IE5+ and Netscape 7 (6?), but the gifs were only 25% as fast with the Netscape browser. And we had thought they only called him Brisk Bill for his rate of company assimilation! Here’s what we learned from the total experience. First the down side to confronting visitors with such web busy pages:
- NEVER put lots of animated gifs on one web page
- Loading time is unacceptable, as is the general frantic context when your page is gif-bloated. And visitors will become angry. People have asked la femme Nikita to "cancel" people for less.
- The browsers can't handle our atest5-animated-and-misc-buttons.html experiment. They're trying to run 16 different special effects at the same time, and they get bogged down, confused, and may bomb. With IE5.5, one can goof up the page operation with pressing the stop button and then the restart—the browser loses track of animation duties and goofs up page function. If you operate the popup menus before an opacity function is done with its operation, you can get a popup stuck, even though the page code says it can't/won't happen. Once you get the browser cache crazy enough, reloading the page won't fix the goofy page function. Only closing the browser and double-clicking this file in your file manager makes it behave correctly again. The browser gets so clogged with gif animating that the blue loading stripe can last forever. The IE browser is running each gif at 5 frames a second, so that’s (16 times 5 =) 80 frames a second. That’s just cruel!
- You'll lose visitors forever and make more enemies than Saddam Hussein
But here's the up side: (There is no up side to putting a site like this on the Net. But there’s plenty of up side to what one can learn from it all.)
- We learned browser limitations—especially how not to treat a browser
- We learned that one can use an animated gif as either the top or bottom button of a rollover
- We learned that a button isn't that great of a use for slowly changing images undergoing opacity transformations. Visitors will get confused. Especially since the button will not return to normal (opaque) until one moves the mouse, but one is as likely as not to stop and stare at the effect, in which case the button will stay "pushed" indefinitely
- We learned to be fast and efficient at animated gif creation
- You may use—but not sell—our buttons and menus in your websites.
Ramifications:
- Use only a few animated gifs per site, and don’t use any unless there's a good reason for them to be there
- If you use a slow opacity effect, use it constructively, not destructively; if you make someone wait, they’ll hate it (no one wants to wait for anything—life’s too short)
- A good use for the animated gifs and Opacity special effects, or the Move operation covered in the atest-buttons-and-menu-tests.html section, is on kids’ sites where you entertain young people with things that disappear, reappear, move mysteriously, or slowly fade; perhaps you'll want sound effects or short movie clips or JavaScript-coded animations as well
- Another good use is animated banner ads, although you may get some people angry; but they seem to be a tried and true marketing tool
- Subtle, nonintrusive animated gifs that are part of a logo are acceptable as long as they don’t bloat page loading times or make visitors wait before they can interact with the page
- A Halloween site with fade-in/fade-out spooks, animated buttons that disappear or only animate when the mouse is over them or that cause strange page occurrences—this is another reasonable place for animated gifs
- A game site where special effects of the types we've discussed are crucial for game play—this is another reasonable place for animated gifs
- One use is to replace the need for Flash (you’ve seen the sites where if you don’t load in a Flash plug-in you can't see the effect; some people either don’t trust Macromedia or don’t want their computer clogged up with plug-ins); it’s true that Flash is less bandwidth intensive than gifs but animated gifs don’t nag users about loading plug-ins nor do they require plug-ins or anything else
- Stylish transitions—this is another reasonable use for animated gifs
- Technical sites that demonstrate a process are another good use
cssbuttonw3cdom.html is 4K. Okay, we forgot some. There are yet other ways to do neat rollovers. Changing border colors can create great buttons, and yet one need only use getElementById and alter CSS style values to get this effect that normally requires loading and exchanging a couple of button images to accomplish. Here's the code:
function buttonupdown(e,c){
if (c=="up"){
document.getElementById("a1").style.borderTopColor='#cccccc';
document.getElementById("a1").style.borderBottomColor='#555555';
document.getElementById("a1").style.borderRightColor='#555555';
document.getElementById("a1").style.borderLeftColor='#cccccc';
}else{
document.getElementById("a1").style.borderTopColor='#555555';
document.getElementById("a1").style.borderBottomColor='#cccccc';
document.getElementById("a1").style.borderRightColor='#cccccc';
document.getElementById("a1").style.borderLeftColor='#555555';
}
}
<div id="a1" class="c" onMouseDown="javascript:buttonupdown('a1','down');return true" onMouseUp="javascript:buttonupdown('a1','up');return true"></div>
.c {border:solid 3px; border-color:#cccccc #555555 #555555 #cccccc; position:absolute; top:200px; left:400px; width:72px; height:28px; background-color:red;}
#a1 {left:200px; background-color:blue;}
All four borders must be dealt with individually, both when declaring the CSS styles and when changing the button from the "up" position to the "down" position, although you can use CSS shorthand in style sheets (as in the "c" class above), but not in JavaScript functions. On the test page, the blue button uses the code above. The buttonupdown() function could take care of a page full of buttons of various styles, colors, and sizes that needed to look pushed and unpushed. But you ain’t seen nothin’ yet.
The top red button is using something that you'll be seeing a lot of in the upcoming Era of the DOM. The DOM will DOMinate just like Arnie can Terminate (or Governate, for that matter). And yet few people seem to have thought of it. You’ve heard about upwardly mobile and such. They're talking about class mobility. It doesn’t take a sociology major to grok that bit of academic parlance. Well, the DOM has class mobility too. One can define classes with tons of rules. Let’s say class c has 27 rules in it and class b has 21 rules. You can change all the CSS styles applied to a page element with one simple function. It uses the little-used className property:
function changeClass(e,n){
document.getElementById(e).className=n;}
Here's the HTML markup and styles for "pushing the top red button.":
<div id="a2" class="c" onMouseDown="javascript:changeClass('a2','b');return true" onMouseUp="javascript:changeClass('a2','c');return true"></div>
.b {border:solid 3px; border-color:#555555 #cccccc #cccccc #555555; position:absolute; top:200px; left:400px; width:72px; height:28px; background-color:red;}
.c {border:solid 3px; border-color:#cccccc #555555 #555555 #cccccc; position:absolute; top:200px; left:400px; width:72px; height:28px; background-color:red;}
Next we’ll look at how one goes about changing a class so that any image will change to any other image. (Note: You may choose to declare a new image and assign the source property so images preload into the cache. We choose not to clutter up our examples with this stuff because in many situations one doesn’t need preloading—although some situations do. It totally depends on the situation. We've encountered websites with preloading of lots of objects which took long enough that we were sure that few visitors would have the patience to wait it out. They'd click away to sites that didn’t act "frozen." What good does it do to use preloads so people’s site interactions are zippy at the first mouse click if the people split on you?) Here's the markup and CSS class styling code for image change via class mobility:
<div id="a3" class="d" onMouseDown="javascript:changeClass('a3','f');return true" onMouseUp="javascript:changeClass('a3','d');return true"></div>
.f {position:absolute; top:300px; left:200px; width:72px; height:28px; background-image:url("n101.jpg");}
.d {position:absolute; top:300px; left:200px; width:72px; height:28px; background-image:url("n116.jpg");}
You'll use the same changeClass() function as above. Click the button with the image on it. Is that cool or what? As Beavis and Butt-head would say, "It doesn’t get any better than this, dude." Of course, you can use this with onMouseOver and onMouseOut or have clicks (onClick) simply change the image, rather than using onMouseDown and onMouseUp.
Now let’s look at a button that’s "like a box of choc-o-lates," as Forrest Gump would say. ("You never know what you're going to get.") It starts with a red button that invites you to "see the status bar." Once you start clicking you'll get a different color every time—one for pushing the mouse button and another for releasing it. There are over 16,000,000 possibilities! Here's the div that calls the colorchange() function:
<div id="a4" class="c" style="top:300px; font:normal 11px Tahoma;" onMouseDown="javascript:colorchange('a4');return true" onMouseUp="javascript:colorchange('a4');return true"> see the<br> status bar</div>
And below are the functions it takes to run it. It takes three. The first runs the Color() function initially to take three random numbers less than 256 and put them into the variables red, green, and blue. The built-in parseInt function is used to turn the decimal numbers into integers. Then the three numbers are turned into one string with # in front of it to make them into a hex color value. Note that in the process of building the string the toHex function is called. The result of each toHex call is treated as a short hex number string, and these strings are concatenated into the long one called hex.
The toHex function itself is a simple decimal-to-hexadecimal converter. Let’s use a sample number 173 and divide it by 16 and dump the decimal component with the built-in Math.floor method. We have 173/16=10 (which gets put into variable i) with 13 left over—which is put into variable j after the modulus operator determines it. Next the function counts i places into the h string which holds all hex characters, and it gets the number A. Actually, the charAt operator is skipping i characters to get to the one it needs, so it can deal with the 0th character in any string too. Then j characters are skipped in the h string to get the number D. Then A and D are concatenated into AD and returned to the calling function Color() to help build the hex string.
Now, back in the poor neglected colorchange() function. We stuff the hex string into c, the color variable. Then, just to prove that we’re too cute by half, we display our color number in the status bar—which explains why you’re told to look there by the message in this button.
function colorchange(e) {Color();c=hex;
document.getElementById(e).style.backgroundColor = c; window.status=("Here is the color you have created: " + c);}
function Color() {red=parseInt(Math.random() * 255);green=parseInt(Math.random() * 255);blue=parseInt(Math.random() * 255);hex = "#" + toHex(red) + toHex(green) + toHex(blue);}
function toHex(dec) {var h = "0123456789ABCDEF";var i = Math.floor(dec / 16);var j = dec % 16;x=h.charAt(i);y=h.charAt(j);return x.toString() + y.toString();}
There are yet other wonders on this page:
<div id="a5"><a HREF="t.html">
Test </a></div>
#a5 {position:absolute; top:250px; left:300px; width:72px; height:28px; text-align:center; font:bold 16px Arial,sans serif;}
The a5 div has a simple text box with a link to the t.html page (which doesn’t actually exist but you're supposed to switch it for a good link). The div and its styles are shown above. Also being applied to it are these link styles, which explains why it acts like a button being depressed:
a, a:visited {text-decoration: none; color:black; width:100%; height:100%; border:solid 3px; border-color:#cccccc #555555 #555555 #cccccc; background-color:green; display:block;}
a:hover {color:black; width:100%; height:100%; border:solid 3px; border-color:#555555 #cccccc #cccccc #555555; background-color:green; display:block;}
Essentially, then, we are doing the same thing with hover as we did with onMouseOver—make the border color changes impersonate a button depression (we were going to say a depressed button but buttons are actually quite happy to be on our test pages). You need the display:block rule very much here because of the NN nerds. One would think that declaring rules about borders around a div box container would help the NN nerds get a clue, since a div is a block element, and borders are used 99.99% of the time on block elements like div (even though it’s technically legal to put borders around inline elements like <i> tagged text). But apparently we were too subtle for them. Anyway, the button is a real screw-up in Netscape without this rule, even though Bill’s Boys don’t need this rule—IE was fine without it.
This is a good way to use pure CSS, without the need for events or running JavaScript functions, to do what used to require JavaScript. People with JavaScript turned off will be surprised to see working buttons! This type of button is best used anywhere but in navigation bars.
Finally, we come to the a6 div, which contains a linked transparent gif with a text message in it. Here are the div, the styles of the a6 id, and the styles of the links for class g which a6 uses. This button lights up rather than depressing. It also, like the a5 button, needs only CSS. This type of button is best in navigation bars.
<div id="a6" class="g"><a HREF="t.html" onfocus="this.blur()"><img src="transp.gif" width="72" height="28" border="0"></a></div>
#a6 {position:absolute; top:350px; left:300px; width:72px; height:28px;}
.g a, .g a:visited {border:none; text-decoration: none; width:100%; height:100%; background-color:gray;}
.g a:hover, .g a:active {border:none; text-decoration: none; width:100%; height:100%; background-color:lightblue;}
You need to be aware that the Netscape and IE browsers are still playing browser war games and displaying differently. So the Netscape height will be more, for most of the buttons. Netscape is obeying the W3C box model specs—adding the border to the box dimensions; IE 5/5.5 is not. But the difference is slight and not worth sweating. If it drives you nuts and you end up nesting divs inside divs in a clever ploy to control display dimensions (one method we've seen kicking around on the Net), or using the DOM model to change dimensions if a button is in the Netscape browser (as you’ve seen us do), good luck. It gets messy—better to ignore slight imperfections like the rest of us.