Advanced Javascript Mouseovers
- Shelley Biotech Example
- Preloading Images
- Mouseovers and Submenus
- Mouseovers and Stylesheets
- Recap
How Rollovers Work
To understand how rollovers actually work, we have to understand how JavaScript sees the world. When a Web page is loaded into a browser, the browser does more than just format and present the HTML for the user to look at. Behind the scenes, the browser also has a JavaScript engine that examines the page as it is being loaded and organizes the page into a formal structure that it can understand. For example, when the JavaScript engine sees the <body> tag, it creates an object called "document" and places all the parts of that page into the document object.
JavaScript follows certain rules when dissecting and organizing a Web page. For example, all of the images on the page, whether they're massive things or tiny, single-pixel gifs, are placed into an array called "images." This images array lives inside the document object. For example, if you wanted JavaScript to look at the first image in your Web page, the code would look like this:
document.images[0]
Remember, arrays start counting at zero, not one.
Using the images array like this when you're creating rollovers is such a bad idea that we're not even going to look at it in an example. We'll look at a few better ways, then come back and see why using image array numbers isn't recommended.
So how else can you point to a certain image using JavaScript? You can give the image a name, then use that name in JavaScript. Let's say we're building a navigation bar with rollovers, and one of the items is "news." Here's what the HTML could look like:
<img name="news" src="images/nav_news_off.gif">
Notice we gave the image the unimaginative but predictable name of "news." So how would you point to this image using JavaScript? There are actually two ways:
document.images['news']
and
document.images.news
These both work fine. In our examples, we'll be using the latter form because it's easier to read.
Replacing Images
So we know how to point to an image, but how do we replace it? Simple: We use the src property of images as follows:
document.images.news.src
You can now assign this src property to any URL that points at an image as in the following:
document.images.news.src = "images/news_on.gif"
or
document.images['news'].src = "http://images.shelleybiotech.com/home/news.gif"
These statements load the new image into the old image's place. It's not a complete replacement, thoughthe new image is loaded into the old image's dimensions. Let's say you have an image that's 100 pixels wide and 200 pixels high. Using the src property, you replace that old image with a new one that's also 100 pixels wide, but it's taller: It's 300 pixels high. That new image will appear in the old image's place, but it will be squashed down to 200 pixels in height. Thus, you have to make sure that when you're replacing one image with another, they are exactly the same size.
Shelley Biotech
Let's start coding. We'll be building the home page for a fictional company called Shelley Biotechnologies. The home page looks like Figure 11.
Figure 11 Shelley Biotech home page
It's pretty simple. What do our rollovers look like? If the user rolls over "Products," it should look like Figure 12.
Figure 12 Rollover example
Before we jump into rollovers, let's build the basic page, which is just comprised of a bunch of images. These images are in Figure 13.
Figure 13 The nonrollover images
You can download all the images and code for this chapter (and all the other chapters) at http://www.wire-man.com/advjs. I recommend ityou'll learn much better when you do the code yourself. The code for the home page (again, without any rollovers yet) is in Example 11.
Example 11 The Shelley home page, sans rollovers
<html> <head> <title>Shelley Biotech</title> <style type="text/css"> #header { position: absolute; left: 30; top: 30;} #tag { position: absolute; left: 250; top: 77;} #gal { position: absolute; left: 514; top: 69;} #nav { position: absolute; left: 0; top: 114;} #feature { position: absolute; left: 10; top: 220;} #copyright { position: absolute; left: 350; top: 490;} </style> </head> <body bgcolor="#FFFFFF" topmargin="0" leftmargin="0"> <div id="header"> <img src="images/shelley_biotech.gif"> </div> <div id="tag"> <img src="images/tag_line.gif"> </div> <div id="gal"> <img src="images/freaky_gal.jpg"> </div> <div id="nav"> <table border="0" cellpadding="0" cellspacing="0"> <tr> <td><img src="images/nav_start.gif"></td> <td> <a href="news/"> <img name="news" src="images/nav_news_off.gif" border="0"></a></td> <td> <a href="products/"> <img name="products" src="images/nav_products_off.gif" border="0"></a></td> <td> <a href="research/"> <img name="research" src="images/nav_research_off.gif" border="0"></a></td> <td> <a href="store/"> <img name="store" src="images/nav_store_off.gif" border="0"></a></td> <td> <a href="about/"> <img name="about" src="images/nav_about_off.gif" border="0"></a></td> </tr> </table> </div> <div id="feature"> <img src="images/features.jpg"> </div> <div id="copyright"> <img src="images/copyright.gif"> </div> </body> </html>
How the Code Works
The only real key to understanding this code is to realize that CSS (or just "stylesheets") are being used to place the images. If stylesheets are new to you, refer to the side note for a quick tutorial.
Cascading Style Sheets
Cascading Style Sheets (CSS) allow you to define chunks of content, or layers, in your HTML page. This happens in two steps. The first step is to define the layer, where you describe its name, where it lives on the Web page, and maybe some other attributes. This is done in the header. In Example 11, it occurred here:
<style type="text/css"> #header { position: absolute; left: 30; top: 30;} </style>
We defined a layer called "header" and said it must be at 30 pixels from the left of the browser window and 30 pixels from the top of the browser window.
This is only the first step. Now that we've defined the layer, we have to create the content that actually lives in the layer. This happens in the body of the Web page.
<div id="header"> <img src="images/shelley_biotech.gif"> </div>
You define a layer by wrapping some HTML with a <div> tag, and giving that <div> tag an "id" matching the name of the layer defined above. In this case, the shelley_biotech.gif image then appears at 30 pixels over and 30 pixels down.
There's a lot more to stylesheets. If you're really interested, by all means check out Essential CSS & DHTML for Web Professionals (by me).
The whole series of navigation images lives in a table. I included an anchor tag, but it obviously doesn't do very much. It's just a placeholder, and we'll be adding to it soon.
Also notice that all of the images in the navigation were given names:
<img name="news" src="images/nav_news_off.gif"> <img name="products" src="images/nav_products_off.gif"> <img name="research" src="images/nav_research_off.gif"> <img name="store" src="images/nav_store_off.gif"> <img name="about" src="images/nav_about_off.gif">
I've taken out the border attribute here so they're easier to read.
Before we get much further, you should see the actual rollover images themselves. Here they are, in Figure 14.
Figure 14 Rollover images
As the code exists right now, these names don't do anything. They just sit there, waiting to be invoked. Let's start with some JavaScript to do that.
Rollover Function
We'll create a single function that handles the rollover and another function to handle the rollout. Let's start with the rollover in Example 12.
Example 12 The rollover function
function rollOver (imgName) { eval("document.images." + imgName + ".src = 'images/nav_" + imgName + "_on.gif'") }
How the Code Works
This may look a little confusing at first, especially if you aren't familiar with the eval() method. Let's step back and look at this method's goal. We want to send it the name of the navigation item that was just rolled over, because it will then swap out the old image for the new one. That is, if the user rolls over the Research image, we want to execute this JavaScript:
document.images.research.src = 'images/nav_research_on.gif'
Since we want the name of the image to allow different values, this line of code has to be able to change:
document.images.NameOfImage.src = 'images/nav_NameOfImage_on.gif'
In other words, we want to dynamically create JavaScript code. The eval() method handles this nicely for us. Eval() works by taking whatever string is inside its parentheses and executing that string as if it were a line of JavaScript code. In this case, if "research" was passed to the function, this is what eval() would see this string:
"document.images.research.src = 'images/nav_research_on.gif'"
Eval() would proceed to execute this code as if it weren't a string, and thus the image nav_research_on.gif replaces nav_research_off.gif.
Great. Now the image is present and the function is in place. All we need to do right now is to call that function at the appropriate time. Example 13 shows the HTML that will do that:
Example 13 Calling the function
<a href="research/" onMouseOver="javascript:rollOver('research')"> <img name="research" src="images/nav_research_off.gif" border="0"></a>
How the Code Works
The code that fires off our rollover function is the onMouseOver bit. Whenever the user's mouse rolls over the image, the JavaScript in the attribute is executed. In this case, the function called rollOver is activated, and the value "research" is sent to that function. Notice that onMouseOver occurs in the anchor tag, not in the image tag. If you haven't done mouseovers before, this can seem a little counterintuitive.
Go ahead and try this code. When you roll over the research image, it should be replaced with the blue-green image. Now roll out. Nothing happens. The research image stays turned on no matter what you do. Clearly, we need a way to set the image back to its original state when the user moves the mouse away from the image. The code to do this is almost exactly like the rollover code:
function rollOut (imgName) { eval("document.images." + imgName + ".src = 'images/nav_" + imgName + "_off.gif'") }
This function is an almost exact copy of the rollOver function we saw earlier. The only thing different about this code is that instead of using _on in the image name, we're using _off. That's it.
But since this is an Advanced JavaScript book, let's alter this a bit. You could easily use the code below instead:
function rollOut (imgName) { document.images[imgName].src = eval("'images/nav_" + imgName + "_off.gif'") }
This isn't wildly differentjust a small tweak that more obviously treats images as an array, and now only the right side of the statement needs an eval() method. It makes no difference to the user which code is usedthe rollover works either way. Choose whichever method you prefer.
This is the only JavaScript we need. The only step that's left is to call these functions from each of the navigation images, as in Example 14.
Example 14 Calling rollover functions from all navigation images
<td> <a href="news/" onMouseOver="javascript:rollOver('news')" onMouseOut="javascript:rollOut('news')"> <img name="news" src="images/nav_news_off.gif" border="0"></a></td> <td> <a href="products/" onMouseOver="javascript:rollOver('products')" onMouseOut="javascript:rollOut('products')"> <img name="products" src="images/nav_products_off.gif" border="0"></a></td> <td> <a href="research/" onMouseOver="javascript:rollOver('research')" onMouseOut="javascript:rollOut('research')"> <img name="research" src="images/nav_research_off.gif" border="0"></a></td> <td> <a href="store/" onMouseOver="javascript:rollOver('store')" onMouseOut="javascript:rollOut('store')"> <img name="store" src="images/nav_store_off.gif" border="0"></a></td> <td> <a href="about/" onMouseOver="javascript:rollOver('about')" onMouseOut="javascript:rollOut('about')"> <img name="about" src="images/nav_about_off.gif" border="0"></a></td>
That's it! To make your life a little easier, here's Example 15, with the whole page in a single listing:
Example 15 The whole page
<html> <head> <title>Shelley Biotech</title> <style type="text/css"> #header { position: absolute; left: 30; top: 30;} #tag { position: absolute; left: 250; top: 77;} #gal { position: absolute; left: 514; top: 69;} #nav { position: absolute; left: 0; top: 114;} #feature { position: absolute; left: 10; top: 220;} #copyright { position: absolute; left: 350; top: 490;} </style> <script language="JavaScript"> function rollOver (imgName) { eval("document.images." + imgName + ".src = 'images/nav_" + imgName + "_on.gif'") } function rollOut (imgName) { document.images[imgName].src = eval("'images/nav_" + imgName + "_off.gif'") } </script> </head> <body bgcolor="#FFFFFF" topmargin="0" leftmargin="0"> <div id="header"> <img src="images/shelley_biotech.gif"> </div> <div id="tag"> <img src="images/tag_line.gif"> </div> <div id="gal"> <img src="images/freaky_gal.jpg"> </div> <div id="nav"> <table border="0" cellpadding="0" cellspacing="0"> <tr> <td><img src="images/nav_start.gif"></td> <td> <a href="news/" onMouseOver="javascript:rollOver('news')" onMouseOut="javascript:rollOut('news')"> <img name="news" src="images/nav_news_off.gif" border="0"></a></td> <td> <a href="products/" onMouseOver="javascript:rollOver('products')" onMouseOut="javascript:rollOut('products')"> <img name="products" src="images/nav_products_off.gif" border="0"></a></td> <td> <a href="research/" onMouseOver="javascript:rollOver('research')" onMouseOut="javascript:rollOut('research')"> <img name="research" src="images/nav_research_off.gif" border="0"></a></td> <td> <a href="store/" onMouseOver="javascript:rollOver('store')" onMouseOut="javascript:rollOut('store')"> <img name="store" src="images/nav_store_off.gif" border="0"></a></td> <td> <a href="about/" onMouseOver="javascript:rollOver('about')" onMouseOut="javascript:rollOut('about')"> <img name="about" src="images/nav_about_off.gif" border="0"></a></td> </tr> </table> </div> <div id="feature"> <img src="images/features.jpg"> </div> <div id="copyright"> <img src="images/copyright.gif"> </div> </body> </html>