MENUS AND BUTTONS Part I
Browsers and the W3C DOM
The best way to make good, dynamic, efficient, robust, effective rollover buttons, menus and other dynamically interactive website features is with DHTML using the W3C DOM (Document Object Model). The method that works best is the getElementById method, which IE 5 or higher or Netscape 6 or better can handle.
Since the number of people using Netscape 4 browsers is almost none—and the same is true of IE 4 and earlier browsers—it’s time to urge people to bury the dead. Version 4 browsers don’t meet today’s W3C standards; they're obsolete. Obsolete browser users are missing out on much rich Internet content as more and more sites (rightly) drop support for them. And the dinosaurs are often doubling and tripling the amount of JavaScript needed on a web page, making for slower loading times and less real content. Even when designers use external JavaScript and CSS files, it still requires a lot more time to code such sites, reducing productivity. And there are features and commands, actual and proposed, in the new CSS3 specs that can't be done in version 4 browsers, which means that dinosaur users are going to be missing out on more and more. We recommend, now that these oldies are a distant memory, that site designers start testing for the absence of W3C DOM compliance with if (!getElementById) and give an appropriate alert if the user has a dinosaur—one that encourages them to update. After all, the newest browsers are very W3C compliant and work really well AND THEY'RE FREE! So, try to get everyone to update. It’s for their own good, not for some corporate profit motive. The newest browsers are free to anyone on Earth who wants them. It’s true that when version 4 browsers replaced version 3 it was a big step up and many people got the erroneous idea that they'd never need to update again. But it’s even more true that the newest major browsers, all of which support the W3C DOM, are a quantum leap up from the version 4 browsers which had clumsy proprietary DOMs that were only a relatively small step in the direction of good DHTML. The W3C has done a lot of work to try to actualize the potential of the Net for great site designs, as have the programmers of IE, Opera, and Netscape. Let’s honor all their efforts on our behalf by doing what the W3C wisely advocates: encourage users to dump the dinos! Or to mix metaphors unforgiveably, we don’t need horse and buggies cluttering up the information superhighway.
Event Handler Testing
In order to have dynamic events occurring courtesy of CSS style changing from JavaScript, we have to test until we determine what works best. This would seem to be a useless quest because button rollovers are traditionally handled by onMouseOver and onMouseOut, so what tests are needed? You'll see. We tried all rollover methods we could logically conjure up and the results surprised us.
Although onMouseOver and onMouseOut are quite effective for some purposes, it turns out that they're not quite as omnipotent as all those beginning JavaScript books would have one believe. In fact, in many ways they are—in the words of Eric Cartman of South Park—"seriously weak." The onMouseOut event handler is slow to respond, and if one jumps out of most of the buttons or menus fast enough when onMouseOut is in effect, it fails entirely. We tried it on all exit operations at first, and rigorous experiments forced us to discard it, one button after another. Go experiment with our buttons and menus test page called atest-buttons-and-menu-tests.html. Note how smooth the menus work. They used NEITHER onMouseOver nor onMouseOut, even though onMouseOut was given a chance here as well and it failed miserably! And of the eight buttons, only two (the one using replace and the one using background color) worked well enough with onMouseOut to be viable, so for the other six buttons we used a different scheme entirely for button exit detection (although onMouseOver worked okay for all buttons). And this turns out to be the same scheme that worked so well for menu exit detection as well as menu proximity detection. Okay, since we know you're drooling to know about our scheme, here it is: we used onMouseMove and mouse coordinate parameter checking. Here's how a mouse coordinate parameter check for button exit looked in the case of leaving the opacity button:
if (op==1&&(y<206||y>235||x<37||x>109)) {op=0;opacity('id51Img',100);}
But, you scream, JavaScript isn't like Apple II or PC DOS where any dummy can read the mouse and respond accordingly after a simple parameter check; JavaScript can't just read the mouse! Or can it? It turns out that what is needed is constant mouse reading and JavaScript can do it for you if you ask nicely. First start things going with an onLoad event:
<BODY SCROLL="auto" BGCOLOR="#FFFFFF" onLoad="startmouse()">
Then let that mouse routine begin. Gentlemen, start your mouses!
var Netscape=(navigator.appName.indexOf("Netscape") != -1);
function startmouse() {if(Netscape) {document.captureEvents(Event.MOUSEMOVE);document.getElementById('id54').style.width=70;}
document.onmousemove=getCoords;
}
function getCoords(e){
if (!e) var e = window.event;
if (e.pageX){
x = e.pageX;
y = e.pageY;
}
else if (e.clientX){
x = e.clientX + document.body.scrollLeft;
y = e.clientY + document.body.scrollTop;
}
We need to know if we’re in a Netscape browser, so we determined that for openers. And since an onMouseMove event handler works in the body tag in IE but only as an event handler in a function in Netscape (there's no good excuse for this; it just simply requires event capturing in Netscape!), we commence event capturing at this time; watch the syntax—the case of the characters is important. The function this event handler is pointed at is the getCoords function. Ignore the silliness about ‘id54’ and width=70. That’s a workaround for a Netscape quirk we’ll look at later in the section about changing the background color.
In the coordinate reading operations in getCoords, take our word for it that this is a good way to read x and y—we tried other ways and this is best. Once we know where x and y are, we compare these values with the rectangles represented by any button and popup pair taken together. Here f is the flag (1 or 0) for "there's a popup popped up somewhere," p is the flag (0 or 1 through 8) for which popup is up, and 73 is (button width + line between buttons). This first code block we’ll look at gets rid of any popup if the mouse cursor is no longer in that popup or its button. The stringum() function figures the correct id names, the a variable gets the concatenated parts of the image source variable for the button gif being used in replace(), the replace function replaces the button, the two box() functions move the popup backdrop image and its text box behind the blue side panel to hide them, and the flag variables are reset to 0 meaning "unset."
if(p>0&&f>0){
if((x<(142+(p-1)*73))||(x>(230+(p-1)*73))||y<117||y>266){
stringum();
a='b' + p + 'x';
replace(i3,a);
box(i1,5,755);
box(i2,4,444);
p=0;f=0;}}(dump popup)
This second code block pops up a popup under the button on which the mouse cursor now resides. The code initially only detects that the mouse is on the rectangle that surrounds all eight buttons, while the division by 73 is the code seeking the value of p (the button number and popup number). This code block only gets used if the conditional rings true. If it does, the stringum() function figures out the correct id and x coordinates, the a variable gets the concatenated parts of the image source variable for the button gif being used in replace(), the replace function replaces the button, the two box() functions move the popup backdrop image and its text box out from behind the blue side panel and under the button, and the flag variables are set.
else if(x>150&&x<733&&y>119&&y<146&&f==0){
f=1;p=parseInt((x-69)/73);
stringum();
a='b' + p + 'l';
replace(i3,a);
box(i1,i5,151);
box(i2,i5,146);}(pop up a popup)
As we've discussed, the menus that pop up and the text boxes that are superimposed on them when they're popped all hide behind the blue side panel when not in use.
Modifying CSS Styles Using getElementById
The first thing to determine when using this method is which styles are most appropriate to modify in order to try to get decent rollover buttons. Not to worry—we've done the grunt work on that one. There are about seven different types of CSS style modification options that come to mind right off the bat for dealing with rollovers: opacity, visibility, display, replace (change img src), move (left), layer (z-index), and background color. We did buttons using each type of operation and the results speak for themselves. All the buttons work good on Netscape 6 or higher or IE 5 or higher, but some have advantages over others. We’ll look at the pros and cons of each of these operations. We created eight buttons instead of seven, because the opacity style suggested an extra option which we call slow opacity. Here are the results of our experiments:
Opacity
This style is part of CSS3 but it’s not even in earlier books about CSS, DHTML, or JavaScript even though both IE and Netscape have somewhat jury-rigged versions of this style. We found a 2001 book that showed IE filter examples but opacity was not even one of the filter types. IE’s version of opacity was easy to work with, comprehensive, and even creative, offering various filter effects. Netscape’s version (MozOpacity) seems very much thrown together at the last minute just to compete with their arch rival Microsoft, but Firefox's and Chrome's and IE's 2014 opacity functions are all the same—just put a number from 0 to 1 into the style like oopp=.5; document.getElementById(g).style.opacity=oopp. The old MozOpacity stuff was no fun to work with, but at least it worked. Opacity’s performance is flawless in all browsers in 2014.
if (op==1&&(y<206||y>235||x<37||x>109)) {op=0;opacity('id51Img',100);}
Note that if we were to use a whole set of buttons (any type) with this parameter checking operation needed in all of them, we’d use the more complex version of parameter checking discussed in Event Handler Testing.
Note also that although the major browsers had quite different opacity syntax (like filter, etc.), in 2014 they agree. All we had to do was use our older (0 to 100) opacity values and divide by 100 to make an opacity style all browsers liked:
function opacity(g,o) {oopp=o/100;document.getElementById(g).style.opacity=oopp;}
The advantage of using this operation for rollovers is that it requires only one button and the labelled navbar underneath, it works great, and the opacity style has great potential for special effects, as do the rest of the IE filters.
Visibility
This style messes up with onMouseOut but not with the exit code below:
if (v==1&&(y<235||y>264||x<37||x>109)) {v=0;show('id52');}
The advantage of using this operation for rollovers is that it requires only one button and an invisible "1-pixel gif" rectangle underneath for the hypertext link, it works okay, and it beats a root canal. Here's the invisible gif’s div code (make sure it comes before the button image div so it gets a lower layer number than the image div in cascade order):
<DIV ID="id1996" style="position:absolute; top:235px; left:37px; width:72px; height:28px;"><A HREF="t.html"><IMG SRC="t.gif" WIDTH=72 HEIGHT=28 BORDER=0></DIV>
Layer
This was a touchy nut to crack, but crack it we did. This style messes up with onMouseOut but not with the exit code below:
if (ll==1&&(y<264||y>292||x<37||x>109)) {ll=0;t=36;r=35;layer('id53','id1918');}
We were surprised to get away with using this reserved word (layer) for a function name. Note that Netscape 4 uses layer a lot. This reminds us of all the dozens of sediment layers that cover dinosaur remains. Even Netscape itself dumped the "layer" operations it used to support in NN4 when it made NN6 and NN7, in favor of the W3C DOM compatible document.getElementById(q).style.zIndex method of dealing with layers via z-index (CSS) and zIndex (JavaScript). Note that in using the function, you have to give the id names of the two elements who will exchange layers whose numbers are t and r.
onMouseOver="ll=1;t=35;r=36;javascript:layer('id53','id1918');return true"
Note also that the div styles need z-index numbers:
<DIV ID="id53" style="position:absolute; top:264px; left:37px; width:72px; height:28px; z-index:36;"
The disadvantage of using this operation for rollovers is that it requires two buttons, but it works great.
Background Color
Now we’ll look at this code that was stuck in the startmouse() function. It’s:
if(Netscape){document.captureEvents(Event.MOUSEMOVE);document.getElementById('id54').style.width=70;}
Ignoring the event capturing, focus on the fact that we just used a convenient Netscape testing conditional to deal with a Netscape quirk. The quirk is that Netscape doesn’t handle div borders, margins, or padding the same as IE, so even though the background color button (‘id54’) is—and looks—72px wide in IE, Netscape widens the button even though we specifically asked for 72px. So we cleverly pushed it back to 72px with the above code by lying and saying to the Netscape nerds that we wanted 70px! Go figure! Okay, we’ll be fair now and quit picking on them: Truth be told, the 1-pixel-wide border we've asked for around the div is supposed to be added to the 72px button width to make the width 74px according to W3C specs. But it’s so inconvenient—it creates extra work and is clumsy! The way IE does it is nicer to work with, so many programmers bemoan this W3C spec, ourselves amongst them. If there was ever a time for all browsers to rebel and do it Bill’s way because it’s better, this is it! Help with the IE box model bug. (Note: Netscape and IE, in addition to the above differences, handle font sizes for the <font> command differently and have slight differences in default font display and monitor assumptions too. Why? Because different programmers programmed them.)
The background color button is the only button on the page that uses actual text in a div rectangle button. The text in the other buttons was done graphically. The background color button works great, but once the link is visited, an annoying dotted enclosure line will be bestowed on the text link to signify that fact if you don’t use the onfocus="this.blur()" event below to quit highlighting the darn thing.
<DIV ID="id54" style="position:absolute; top:293px; left:37px; width:72px; height:28px; border:1px solid #000; background-color:#0482fc; text-align:center; vertical-align:center; font:bold 11px Tahoma, sans-serif;"><A HREF="t.html" onfocus="this.blur()" onMouseOver="javascript:backgrnd('id54','#84fefc');return true" onMouseOut="javascript:backgrnd('id54','#0482fc');return true">background<br>color</a></DIV>
Something to note here because of the wizards at Netscape: the word background wasn’t spelled out in the function name because Netscape has decided that it’s a reserved word, which we quickly deduced from the fact that it wouldn’t work spelled out, although IE couldn’t care less, as evidenced by the fact that it worked spelled out with IE. Oh, lest we forget, onMouseOut actually works good with this button.
The advantage of using this type of rollover is that it doesn’t need any buttons (a great time and page memory saver for page loading) and it is swift and flawless. It’s just a colored div whose color one can change easily with a mouseover. The disadvantage is you have to mess with text formatting and Netscape will get cute (albeit compliantly so) about the overall div size so you may have to lie about button (in this case a text box) width.
Here's the backgrnd() function:
function backgrnd( t, r ) {c='#84fefc';if(!r)c='#0482fc';
document.getElementById(t).style.backgroundColor = c;}
It just uses the r flag (0 or 1) to determine the color to use and the Netscape flag to determine the syntax of the color. The variable t is element id.
Replace
Don’t forget to use these new image and image source replacement codes when using replacement operations.
var s5l=new Image();
var s5x=new Image();
s5l.src='side-5lit.gif';
s5x.src='side-5.gif';
Here’s the replace function:
function replace( q, r ) {r=eval(r);var s=q+'Img';var e=document.getElementById(s);if(e.src&&r&&r.src){e.src=r.src;}}
Don’t forget to use the built-in JavaScript function eval() in your replace function, as we did, or it will mess up. Here's why: In the getCoords function, we use:
a='b' + p + 'x';
replace(i3,a);
We are building a variable name to put into the variable a. This variable name, let’s say b1x, is going to be used to exchange image source codes in a div via the replace function. But even though we built up the correct variable name and stuck it in the variable called a, what we've built is a string. The eval() function tries to evaluate whatever you send to it as JavaScript commands, so it prefers to see b1x as a variable name, not a string. This is good, since e.src=r.src types of image source operations work on variable names but not strings trying to impersonate variable names. Of course, we could use an actual variable name in a parameter in calling replace (e.g., replace(i3,b1x); ). This would eliminate the need for eval() in replace. But if we did that, we’d need 16 separate instances of calling replace(): 8 for mouse over and 8 for mouse out. That’s why the getCoords function has only two replace() calls, one after a='b' + p + 'x'; (the popup eraser) and one after a='b' + p + 'l'; (the popup popper). The p variable represents which of the 8 popup buttons are being addressed, so a different button needs addressing for each popup. There's nothing difficult about using a switch conditional and having 8 cases stem from the p variable, but the code is inefficient and inelegant. Better to create a string about a variable and run it through eval() to variable-ize it.
The advantage of using this traditional, normal replace method is that it works okay with the onMouseOut event handler and it works better with older browsers. The disadvantages of using this operation for rollovers are that it needs the above image source replacement codes and it requires that you preload two buttons, but it works great if you don’t mind the extra load time and extra page memory use. We even used the replace operation in the popup menus, although we could have used something that had fewer button loading requirements. We liked it because its preloading (which is what that new image() and assigning the source property stuff is for) means that the buttons will be immediately responsive to a visitor because they're already cached.
Move
Note where we move the button for the rollover effect:
javascript:move('id56',-73)
It goes into the twilight zone of minusville—off the web page entirely. A good hiding place by any measure. It’s modifying the left style property. This style messes up with onMouseOut but not with the exit code below:
if (mv==1&&(y<351||y>379||x<37||x>109)) {mv=0;move('id56',37);}
The advantage of using this operation for rollovers is that it requires only one button and an invisible "1-pixel gif" underneath, it works great, and the move function has a lot of special effects potential.
Display
This style messes up with onMouseOut but not with the exit code below:
if (d==1&&(y<380||y>409||x<37||x>109)) {d=0;display('id57','inline');}
The advantage of using this operation for rollovers is that it requires only one button and an invisible "1-pixel gif" underneath, it works great, and it’s even possible to affect the page layout. When you change an element’s display value to "none," not only does the element disappear; the space it took up on the page layout goes away and its children are gone too. Unfortunately, this is the liability of the display style as well, since you may only desire an element to disappear without any other consequence. If so, use the visibility style instead.
Slow Opacity
This style messes up with onMouseOut but not with the exit code below:
if (sl==1&&(y<409||y>438||x<37||x>109)) {sl=0;g='id58Img';slowopacity(0);}
The function that makes the opacity gradual works for onMouseOver (it goes from 100% to 0% opaque) and button exit (it goes from 0% to 100% opaque). The letter variable below is a letter, not a zero. Here's the function. Note that you can run a function inside another function.
function slowopacity(o) {
if (sl==0){
if (o < 100) {
o = o + 10;
opacity(g,o); (calling the function opacity() from within the slowopacity() function)
setTimeout("slowopacity(" + o + ")", 100);
}
}
else{
if (o > 0) {
o = o - 10;
opacity(g,o);
setTimeout("slowopacity(" + o + ")", 100);
}
}
}
Note the strange CSS style codes in the div that try to please IE and Netscape simultaneously. The moz syntax is a dead giveaway that Mozilla/Netscape styles are being addressed. This style code is also needed for the opacity operation discussed earlier.
style="position:absolute; top:409px; left:37px; width:72px; height:28px; filter:alpha(opacity=100);-moz-opacity:1.0;"
The advantage of using this operation for rollovers is that it requires only one button and the labelled navbar underneath, it works great, and the opacity style has great potential for special effects, as do the rest of the IE filters.
You’ve Met the Contenders—So Who Wins?
Opacity and Slow Opacity win for the most special effects potential, especially the way IE does it with their non-standard data type called a filter (don’t smile, Bill, we know that your motto is "resistance is futile—we will assimilate" and we’re wise to you). Move is a close second in the special effects area. The least code, least time to load, and least page memory used awards all go to the Background Color operation, but keep in mind the Netscape quirk (even if it is W3C compliant, we still consider it a quirk because it’s unwieldy) and the text formatting hassle.
Text Links on the Popup Menus
Here's the CSS styling section in the page’s head section:
<STYLE TYPE="text/css">
BODY {margin-left:0; margin-right:0; margin-top:0; font:normal 13px Arial, sans-serif;}
a {text-decoration: none;}
a:hover {color:#000000; background-color:#c0c0c0}
a:active {color:#ff0000; background-color:#808080}
#id54 a {color:black; background-color:transparent}
#id1933 a {background-color:transparent}
#id1999 a {background-color:transparent}
#id1996 a {background-color:transparent}
</STYLE>
Rules contain selectors, properties and values in this configuration: selector {property: value;}. The rules above are not necessarily permanent, nor are the ones in the divs of the HTML code. Most styles can be altered with DOM methods—dynamically. The first four rules above are for the text in the popup menus. They keep the link indications looking nice—they even look like little buttons due to the use of the background-color style property. The text boxes are placed via absolute positioning superimposed over the popup images.
We’d have embedded all styles in the head section if we thought it would be best to teach with—but we didn’t think that, so we just selected these few rules for the head. Keeping the styles inline with the divs can help a lot with giving you a clear sense of what is going on in that div, even though if we were designing a website we’d be putting most styles in style sheets. The id54 rule above is to keep the background color of non-popup link text transparent so the background color of the div (not the link) is seen, since this is the button that changes div background color only—there is no image. The last three rules are to keep the background color of non-popup link boxes (1-pixel gif invisible object rectangles) transparent so the navbar text underneath shows through for those three buttons.
<DIV ID="id1996" style="position:absolute; top:235px; left:37px; width:72px; height:28px;"><A HREF="t.html"><IMG SRC="t.gif" WIDTH=72 HEIGHT=28 BORDER=0></DIV>
Note that the invisible gif object above serves only one purpose—holding the link. Links have to relate to text or images.
Browser Bug ?
So what's your take on all this, is there an onMouseOut bug in all the browsers? You can clearly see that a simple x-y proximity checker runs rings around the onMouseOut event handler in all cases. OnMouseOut fails completely in many cases—more in Netscape than in IE—and without the proximity checker any flubbed rollover button operation we tried would have been seen as nonviable. So what's going on here? Why was it necessary to dump onMouseOut for six of eight buttons after extensive testing, and to use our programming savvy to come up with something better? Curiouser and curiouser . . .
It turns out that from their perspective, there's either no bug or just a teeny one, while from our perspective, there's a whopper. But we’d like to sneak up on where we’re going here, not jump on it like a jaguar on an antelope.
Let’s look at a WYSIWYG web page editor called Cool Page (version 2.72). We've created lots of menus and rollovers with that, but you can only go so far, as the highest level version (2.72) of the program at this writing supports events but not HTML coding to fine-tune the effectiveness of the events. This is okay for many types of rollover effects, but it’s weak for popup menu creation. We had to create a complex set of huge, invisible boxes with this editor to try to catch the onMouseOut failures, which took tons of memory and load time. And even then menus sometimes came up before another one had been erased—that’s weak. It was obvious that a flag was needed to keep the popups from popping if any other popup was still displayed. We ended up having to do the flag system in HTML as it was impossible to address it from Cool Page. But why go through all this hassle for onMouseOut flubs when a couple lines of proximity-checking HTML code solves the problem simply and flawlessly without ever having to dirty one’s hands with onMouseOuts? The answer is that there are so many beginners that find neat little editors like Cool Page very useful for site creation that doesn’t require learning HTML or DHTML. These people have no way of knowing about the simple and flawless and extremely compact code fix, and that editor isn't set up to let them utilize such fixes anyhow.
But back to the point—why did onMouseOut mess up in both Cool Page and our button and menu experiments in the atest-buttons-and-menu-tests.html file? Referring only to our current test page now, it wasn’t much use for menus, and even button exits didn’t always make buttons erase. Why? It worked okay (except for the total failures) if one moved off a button or popup slowly or even medium fast. But for the tens of millions of us "power users" that whip around from one task to the next on our machines, it was seriously weak. It turns out that onMouseOut wasn’t built to catch whip-speed events, just normal speed. But normal should have been defined as anything from slow to whip speed. It wasn’t. So we contend that onMouseOut was programmed wrong in the major (we’re too lazy to test the minor ones) browsers. (Cheer up Bill and NN nerds—we’ll tell you how to fix it!)
This next part will make the browser programmers say "gotcha" but we’ll reply: "oh no you didn’t." For the visibility, move, opacity, display, and layer buttons, it messed up, but for the background color and replace buttons it worked pretty good. JavaScript experts have already figured out the following, of course, but may not have thought about all the ramifications. The reason it worked good on background color was that we were just switching colors on a div-layer-object. The object didn’t go away in any way, shape or form. So it was one of those best-case-scenarios for onMouseOut. A static div. For the other button operations beside replace: they all went away or got defined as if they had, so onMouseOut decided that there was nothing to act upon. The display button ceased to exist. The opacity and visibility buttons merely became invisible but IE defined the latter (for onMouseOut purposes) as if it had left town and Netscape defined both buttons as MIA in that context. Layer got confused because we were switching divs’ actual z-index (layer) value. And move took off for the Bahamas leaving a perfectly good stand-in in its place (even if a bit weak in the visibility department), but onMouseOut was having none of it.
But the definition of DHTML is an environment in which objects are dealt with DYNAMICALLY—hence the name, therefore a browser claiming to handle DHTML should use the onMouseOut event handler dynamically. They could do what we did with the proximity checkers and all problems would disappear like donuts at a cop convention.
But they’ve stuck us with the operations called replace and background color change and little else, although there are more options with these buttons’ compatibility with onMouseOver if you needn't have your images be links. (Actually, there are even more options beyond the eight types of operations we've explored—keep reading until you get to the next page, a section about cssbuttonw3cdom.html, a file that adds some frosting to the cake that this entire article represents.) Our replace button was the hero here in that even though one image replaced another, it stayed right in the same div to do it, merely changing the image source. onMouseOut trembled with delight. We didn’t. It takes two button images per button and extra source defining code and two divs one superimposed upon the other in page layout, excess memory and longer load times and all this because people are used to doing it that way and it’s onMouseOut friendly? All this because people are too lazy (or too conformist?) to use a proximity checker that makes all eight of our buttons work perfectly for both button entrance and exit with relatively little code and with any type of button or CSS property change? What's the payoff? Being "normal"? Shudder . . .
So the experts would tell us that the onMouseOut event handler must only deal with the existentially real, not some phantom div lurking in short term memory. They’d probably ask us to think of a house. One can remodel the interior from Early Victorian to Early Borg and the house is still there—it’s just different. The décor that just happens to be centered on hundreds of logos of assimilated, bankrupted, and killed companies all over the study wall may be unusual, and the wallpaper in the den that repeats the pattern IBM-PC over and over and then when you get close and see that these five letters are only the first letters of the words I Believe in Merciless Predatory Capitalism it really starts seeming eccentric, but that’s nothing compared to finding Jeri Ryan in a yummy blue cat suit and chained to a chair in the living room watching Voyager reruns as she sobs to be freed (of course it’s all an act and she's only there "acting" that way because the owner was willing to pay a million bucks a day to flaunt his wealth this way and she couldn’t turn down being "assimilated" in this way). Now that’s conspicuous consumption!
But we digress. You can see that the house’s transformation from Early Victorian to Early Borg is about how it looks inside, which is analogous to a div getting a different image source and therefore appearing to be different, via a replace operation. The mouse is still in the house and it knows it. If the mouse scampers out it knows that "I was just in, but now I'm out." There's something that it just exited—something existentially solid. But if display or visibility or move is the CSS property value that changes, it’s like the house suddenly vanishing and the mouse would be left standing on a vacant lot scratching his head, and it wouldn’t be exiting a house if it scampered away since there's nothing to exit. The same would be true with opacity making the house vanish, for Netscape, but not IE. And layer simply gets the poor little mousey all confused—as if the mouse suddenly got transported from the Early Victorian house to the Borg/Gates’ house, or as if the Borg/Gates’ house suddenly assimilated the Early Victorian house (resistance was futile) and therefore when it books out of there at warp speed no onMouseOut is relevant because the Early Victorian house it was in before is not the one being exited. Anyway, that’s what the experts would say. And of course, they're right. And who could argue with such dazzling brilliance as that anyway? One can only reply with: "gasp!"
But, experts’ brilliance notwithstanding, here's our take: onMouseOver works okay because it either does or doesn’t do its thing—depending on how fast you traverse the button. A simple task. End of story. But onMouseOut should either be redone to be a proximity checker like we've discussed or JavaScript should add a new event handler called onCoordsOut. This latter would do what a decent DHTML event handler should: respond to the fact that the user is no longer within some button’s coordinates. Don’t sweat the fact that the button may have "taken a hike" in some fashion—forget whether the button operation is display, visibility, replace, opacity, layer, move, background color or "beam me up, Scotty." The programmer’s obvious intention if s/he stuck an onMouseOut along with an onMouseOver is to catch any mouse exit. Period! onMouseOver can simply memorize the coordinates, length, width, and id for the last onMouseOver’ed button or div that had an onMouseOut in the div as well (if it doesn’t, memorize nothing), and the onMouseOut can try to function but no sweat because if it fails, the programmer has a backup plan: he or she has an onLoad= "onCoordsOut()" in the body tag which is a built-in event handler (like onMouseOver) that proximity checks via x-y coordinates.
It needs no argument or anything; it just needs to be started up (initialized). It keeps checking for the mouse being out of the coordinate range of the last button that has been onMouseOver’ed and that has an onMouseOut. It keeps checking only until the button gets put back to pre-onMouseOver status due to the available onMouseOut, or because onCoordsOut put back the button, and changed its page coordinate values, display value, visibility value, layer (z-index) value and so on back the way they were pre-onMouseOver. It has nothing to do until the next onMouseOut needs aid. One really important detail is that once the onCoordsOut detects an onMouseOver for a button that has an onMouseOut, it will allow no other onMouseOver to function until an onMouseOut happens for that button or onCoordsOut puts back the button that onMouseOut missed. The exception is onMouseOvers in divs or wherever that have no onMouseOut, signifying that the website designer wanted the onMouseOver response to be permanent—never to be reversed. onCoordsOut ignores these.
If our ideas get acted upon by the major players, here are the benefits:
- Any website designer can use onMouseOver/onMouseOut pairs on any site without regard to whip movements that used to make onMouseOut fail
- Any website designer can use onMouseOver/onMouseOut pairs on any site without regard to whether the onMouseOver changes CSS style properties like display, left, visibility, opacity, or z-index, giving the onMouseOut event handler greatly increased effectiveness, accuracy, scope, and ease of use
- Browser programmers get to cover their sixes with regards to the sloppy job they did with onMouseOut since there's now a great backup feature
- WYSIWYG editors such as Cool Page (version 2.72) get to add onCoordsOut (or use a newly revamped onMouseOut event handler that works right) to their events choices and this will cure all the things that used to mess up
- The W3C gets to either rework their definitions of how one can use onMouseOut for any kind of exiting where onMouseOver has been triggered, or they get to add the new onCoordsOut event handler, complete with a nice set of syntax and operation rules
- We get to name a new JavaScript event handler and get bragging rights
- Bill (a.k.a., "the Assimilator"—soon to go up against Arnie "the Governator" in a World Wrestling Federation extreme mud wrestling event) will get that damned grin off his face