User:Moncur/15
15. Unobtrusive Scripting
[wax ka badal]Scripting Best Practices
[wax ka badal]As you start to develop more complex scripts, it's important to know some scripting best practices. These are guidelines for using JavaScript that more experienced programmers have learned the hard way. Here are a few of the benefits of following these best practices:
- Your code will be readable and easy to maintain, whether you're turning the page over to someone else or just trying to remember what you did a year ago.
- You'll create code that follows standards, and won't be crippled by a new version of a particular browser.
- You'll create pages that work even without JavaScript.
- It will be easy to adapt code you create for one site to another site or project.
- Your users will thank you for creating a site that is easy to use, and easy to fix when things go wrong.
Whether you're writing an entire AJAX web application or simply enhancing a page with a three-line script, it's useful to know some of the concepts that are regularly considered by those who write complex scripts for a living. The following sections introduce some of these best practices.
Content, Presentation, and Behavior
[wax ka badal]When you create a web page, or especially an entire site or application, you're dealing with three key areas: content, presentation, and behavior.
- Content consists of the words that a visitor can read on your pages. You create the content as text, and mark it up with HTML to define different classes of contentheadings, paragraphs, links, and so on.
- Presentation is the appearance and layout of the words on each pagetext formatting, fonts, colors, and graphics. Although it was common in the early days of the Web to create the presentation using HTML only, you can now use Cascading Style Sheets (CSS) to define the presentation.
- Behavior is what happens when you interact with a page—items that highlight when you move over them, forms you can submit, and so on. This is where JavaScript comes in, along with server-side languages such as PHP.
It's a good idea to keep these three areas in mind, especially as you create larger sites. Ideally, you want to keep content, presentation, and behavior separated as much as possible. One good way to do this is to create an external CSS file for the presentation and an external JavaScript file for the behavior, and link them to the HTML document.
Keeping things separated like this makes it easier to maintain a large site—if you need to change the color of the headings, for example, you can make a quick edit to the CSS file without having to look through all of the HTML markup to find the right place to edit. It also makes it easy for you to reuse the same CSS and JavaScript on multiple pages of a site. Last, but not least, this will encourage you to use each language where its strengths lie, making your job easier.
Progressive Enhancement
[wax ka badal]One of the old buzzwords of web design was graceful degradation. The idea was that you could build a site that used all of the bells and whistles of the latest browsers, as long as it would "gracefully degrade" to work on older browsers. This mostly meant testing on a few older browsers and hoping it worked, and there was always the possibility of problems in browsers that didn't support the latest features.
Ironically, you might expect browsers that lack the latest features to be older, less popular ones, but some of the biggest problems are with brand-new browsers—those included with mobile phones and other new devices, all of which are primitive compared to the latest browsers running on computers.
One new approach to web design that addresses this problem is known as progressive enhancement. The idea is to keep the HTML documents as simple as possible, so they'll definitely work in even the most primitive browsers. After you've tested that and made sure the basic functionality is there, you can add features that make the site easier to use or better looking for those with new browsers.
If you add these features unobtrusively, they have little chance of preventing the site from working in its primitive HTML form. Here are some guidelines for progressive enhancement:
- Enhance the presentation by adding rules to a separate CSS file. Try to avoid using HTML markup strictly for presentation, such as <b> for boldface or <blockquote> for an indented section.
- Enhance behavior by adding scripts to an external JavaScript file.
- Add events without using inline event handlers, as described in [Hour 9], "Responding to Events," and later in this hour.
- Use feature sensing, described later this hour, to ensure that JavaScript code only executes on browsers that support the features it requires.
- By the Way
- The term progressive enhancement first appeared in a presentation and article on this topic by Steve Champeon. The original article, along with many more web design articles, is available on his company's website at http://hesketh.com/.
Adding Event Handlers
[wax ka badal]In [Hour 9], you learned that there is more than one way to set up an event handler. The simplest way is to add them directly to an HTML tag. For example, this <body> tag has an event handler that calls a function called Startup.
<body onLoad="Startup();">
This method still works, but it does mean putting JavaScript code in the HTML page, which means you haven't fully separated content and behavior. To keep things entirely separate, you can set up the event handler in the JavaScript file instead, using syntax like this:
window.onload=Startup;
Right now, this is usually the best way to set up events: It keeps JavaScript out of the HTML file, and it works in all browsers since Netscape 4 and Internet Explorer 4. However, it does have one problem: You can't attach more than one event to the same element of a page. For example, you can't have two different onLoad event handlers that both execute when the page loads.
When you're the only one writing scripts, this is no big deal—you can combine the two into one function. But when you're trying to use two or three third-party scripts on a page, and all of them want to add an onLoad event handler to the body, you have a problem.
The W3C Event Model
[wax ka badal]To solve this problem and standardize event handling, the W3C created an event model as part of the DOM level 2 standard. This uses a method, addEventListener(), to attach a handler to any event on any element. For example, the following uses the W3C model to set up the same onLoad event handler as the previous examples:
window.addEventListener('load', Startup, false);
The first parameter of addEventListener() is the event name without the on prefix—load, click, mouseover, and so on. The second parameter specifies the function to handle the event, and the third is an advanced flag that indicates how multiple events should be handled. (false works for most purposes.)
Any number of functions can be attached to an event in this way. Because one event handler doesn't replace another, you use a separate function, removeEventListener(), which uses the same parameters:
window.removeEventListener('load', Startup, false);
The problem with the W3C model is that Internet Explorer (as of versions 6 and 7) doesn't support it. Instead, it supports a proprietary method, attachEvent(), which does much the same thing. Here's the Startup event handler defined Microsoft-style:
window.attachEvent('onload', Startup);
The attachEvent() method has two parameters. The first is the event, with the on prefix—onload, onclick, onmouseover, and so on. The second is the function that will handle the event. Internet Explorer also supports a detachEvent() method with the same parameters for removing an event handler.
Attaching Events the Cross-Browser Way
[wax ka badal]As you can see, attaching events in this new way is complex and will require different code for different browsers. In most cases, you're better off using the traditional method to attach events, and that method is used in most of this book's examples. However, if you really need to support multiple event handlers, you can use some if statements to use either the W3C method or Microsoft's method. For example, the following code adds the ClickMe() function as an event for the element with the id attribute btn:
obj = document.getElementById("btn'); if (obj.addEventListener) { obj.addEventListener('click',ClickMe,false); } else if (obj.attachEvent) { obj.attachEvent('onclick',ClickMe); } else { obj.onclick=ClickMe; }
This checks for the addEventListener() method, and uses it if it's found. Otherwise, it checks for the attachEvent() method, and uses that. If neither is found, it uses the traditional method to attach the event handler. This technique is called feature sensing and is explained in detail later this hour.
Many universal functions are available to compensate for the lack of a consistent way to attach events. If you are using a third-party library, there's a good chance it includes an event function that can simplify this process for you.
- Did you Know?
- The Yahoo! UI Library includes an event-handling function that can attach events in any browser, attach the same event handler to many objects at once, and other nice features. See http://developer.yahoo.net/yui/ for details, and see [Hour 8], "Using Built-in Functions and Libraries," for information about using third-party libraries.
Web Standards: Avoid Being Browser Specific
[wax ka badal]The Web was built on standards, such as the HTML standard developed by the W3C. Now there are a lot of standards involved with JavaScriptCSS, the W3C DOM, and the ECMAScript standard that defines JavaScript's syntax.
Right now, both Microsoft and the Mozilla Project are improving their browsers' support for web standards, but there are always going to be some browser-specific, nonstandard features, and some parts of the newest standards won't be consistently supported between browsers.
Although it's perfectly fine to test your code in multiple browsers and do whatever it takes to get it working, it's a good idea to follow the standards rather than browser-specific techniques when you can. This ensures that your code will work on future browsers that improve their standards support, whereas browser-specific features might disappear in new versions.
- By the Way
- One reason to make sure you follow standards is that your pages can be better interpreted by search engines, which often helps your site get search traffic. Separating content, presentation, and behavior is also good for search engines because they can focus on the HTML content of your site without having to skip over JavaScript or CSS.
Documenting Your Code
[wax ka badal]As you create more complex scripts, don't forget to include comments in your code to document what it does, especially when some of the code seems confusing or is difficult to get working. It's also a good idea to document all of the data structures and variables, and function arguments used in a larger script.
Comments are a good way to organize code, and will help you work on the script in the future. If you're doing this for a living, you'll definitely need to use comments so that others can work on your code as easily as you can.
Usability
[wax ka badal]While you're adding cool features to your site, don't forget about usability—making things as easy, logical, and convenient as possible for users of your site. Although there are many books and websites devoted to usability information, a bit of common sense goes a long way.
For example, suppose you use a drop-down list as the only way to navigate between pages of your site. This is a common use for JavaScript, and it works well, but is it usable? Try comparing it to a simple set of links across the top of a page.
- The list of links lets you see at a glance what the site contains; the drop-down list requires you to click to see the same list.
- Users expect links and can spot them quickly—a drop-down list is more likely to be part of a form than a navigation tool, and thus won't be the first thing they look for when they want to navigate your site.
- Navigating with a link takes a single click—navigating with the drop-down list takes at least two clicks.
Remember to consider the user's point of view whenever you add JavaScript to a site, and be sure you're making the site easier to use—or at least not harder to use. Also make sure the site is easy to use even without JavaScript.
Design Patterns
[wax ka badal]If you learn more about usability, you'll undoubtedly see design patterns mentioned. This is a computer science term meaning "an optimal solution to a common problem." In web development, design patterns are ways of designing and implementing part of a site that webmasters run into over and over.
For example, if you have a site that displays multiple pages of data, you'll have "Next Page" and "Previous Page" links, and perhaps numeric links for each page. This is a common design pattern—a problem many web designers have had to solve, and one with a generally agreed-upon solution. Other common web design patterns include a login form, a search engine, or a list of navigation links for a site.
Of course, you can be completely original and make a search engine, a shopping cart, or a login form that looks nothing like any other, but unless you have a way of making them even easier to use, you're better off following the pattern, and giving your users an experience that matches their expectations.
Although you can find some common design patterns just by browsing sites similar to yours and noticing how they solved particular problems, there are also sites that specialize in documenting these patterns, and they're a good place to start if you need ideas on how to make your site work.
- Did you Know?
- The Yahoo! Developer Network documents a variety of design patterns used on their network of sites, many of which are implemented using JavaScript: http://developer.yahoo.net/ypatterns/.
Accessibility
[wax ka badal]One final aspect of usability to consider is accessibility—making your site as accessible as possible for all users, including the disabled. For example, blind users might use a text-reading program to read your site, which will ignore images and most scripts. More than just good manners, accessibility is mandated by law in some countries.
The subject of accessibility is complex, but you can get most of the way there by following the philosophy of progressive enhancement: Keep the HTML as simple as possible, keep JavaScript and CSS separate, and make JavaScript an enhancement rather than a requirement for using your site.
Reading Browser Information
[wax ka badal]In [Hour 4], "Working with the Document Object Model (DOM)," you learned about the various objects (such as window and document) that represent portions of the browser window and the current web document. JavaScript also includes an object called navigator that you can use to read information about the user's browser.
The navigator object isn't part of the DOM, so you can refer to it directly. It includes a number of properties, each of which tells you something about the browser. These include the following:
- navigator.appCodeName is the browser's internal code name, usually Mozilla.
- navigator.appName is the browser's name, usually Netscape or Microsoft Internet Explorer.
- navigator.appVersion is the version of the browser being used—for example, 4.0(Win95;I).
- navigator.userAgent is the user-agent header, a string that the browser sends to the web server when requesting a web page. It includes the entire version information—for example, Mozilla/4.0(Win95;I).
- navigator.language is the language (such as English or Spanish) of the browser. This is stored as a code, such as "en_US" for U.S. English. This property is supported only by Netscape and Firefox.
- navigator.platform is the computer platform of the current browser. This is a short string, such as Win16, Win32, or MacPPC. You can use this to enable any platform-specific features—for example, ActiveX components.
- By the Way
- As you might have guessed, the navigator object is named after Netscape Navigator, the browser that originally supported JavaScript. Fortunately, this object is also supported by Internet Explorer and most other recent browsers.
Displaying Browser Information
[wax ka badal]As an example of how to read the navigator object's properties, [Listing 15.1] shows a script that displays a list of the properties and their values for the current browser.
- Listing 15.1. A Script to Display Information About the Browser
<html> <head> <title>Browser Information</title> </head> <body> <h1>Browser Information</h1> <hr> <p> The <b>navigator</b> object contains the following information about the browser you are using. </p> <ul> <script language="JavaScript" type="text/javascript"> document.write("<li><b>Code Name:</b> " + navigator.appCodeName); document.write("<li><b>App Name:</b> " + navigator.appName); document.write("<li><b>App Version:</b> " + navigator.appVersion); document.write("<li><b>User Agent:</b> " + navigator.userAgent); document.write("<li><b>Language:</b> " + navigator.language); document.write("<li><b>Platform:</b> " + navigator.platform); </script> </ul> <hr> </body> </html>
This script includes a basic HTML document. A script is used within the body of the document to display each of the properties of the navigator object using the document.write() statement.
To try this script, load it into the browser of your choice. If you have more than one browser or browser version handy, try it in each one. Firefox's display of the script is shown in [Figure 15.1].
Dealing with Dishonest Browsers
[wax ka badal]If you tried the browser information script in [Listing 15.1] using one of the latest versions of Internet Explorer, you probably got a surprise. [Figure 15.2] shows how Internet Explorer 6.0 displays the script.
There are several unexpected things about this display. First of all, the navigator.language property is listed as undefined. This isn't much of a surprise because this property isn't yet supported by Internet Explorer.
More important, you'll notice that the word Mozilla appears in the Code Name and User Agent fields. The full user agent string reads as follows:
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Believe it or not, Microsoft did have a good reason for this. At the height of the browser wars, about the time Netscape 3.0 and IE 3.0 came out, it was becoming common to see "Netscape only" pages. Some webmasters who used features such as frames and JavaScript set their servers to turn away browsers without Mozilla in their user agent string. The problem with this was that most of these features were also supported by Internet Explorer.
Microsoft solved this problem in IE 4.0 by making IE's user agent read Mozilla, with the word compatible in parentheses. This allows IE users to view those pages, but still includes enough details to tell web servers which browser is in use.
You've probably already noticed the other problem with Internet Explorer 6.0's user agent string: the portion reading Mozilla/4.0. Not only is IE claiming to be Netscape, but it's also masquerading as version 4.0. Why?
As it turns out, this was another effort by Microsoft to stay one step ahead of the browser wars, although this one doesn't make quite as much sense. Because poorly written scripts were checking specifically for "Mozilla/4" for dynamic HTML pages, Microsoft was concerned that its 5.0 version would fail to run these pages. Since changing it now would only create more confusion, this tradition continues with IE 6.0.
- By the Way
- Microsoft isn't alone in confusing browser IDs. Netscape version 6 displays a user agent string beginning with Mozilla/5, and an app version of 5.0. (Netscape 5.0 was Netscape's open-source browser, code named Mozilla, which formed the foundation of Netscape 6 and Firefox.)
Although these are two interesting episodes in the annals of the browser wars, what does all this mean to you? Well, you'll need to be careful when your scripts are trying to differentiate between IE and Netscape, and between different versions. You'll need to check for specific combinations instead of merely checking the navigator.appVersion value. Fortunately, there's a better way to handle this, as you'll learn in the next section.
Cross-Browser Scripting
[wax ka badal]If all of those details about detecting different browser versions seem confusing, here's some good news—in most cases, you can write cross-browser scripts without referring to the navigator object at all. This is not only easier, it's better, because browser-checking code is often confused by new browser versions, and has to be updated each time a new browser is released.
Feature Sensing
[wax ka badal]Checking browser versions is sometimes called browser sensing. The better way of dealing with multiple browsers is called feature sensing. In feature sensing, rather than checking for a specific browser, you check for a specific feature. For example, suppose your script needs to use the document.getElementById() function. You can begin a script with an if statement that checks for the existence of this function:
if (document.getElementById) { // do stuff }
If the getElementById function exists, the block of code between the brackets will be executed. Another common way to use feature sensing is at the beginning of a function that will make use of a feature:
function changeText() { if (!document.getElementById) return; // the rest of the function executes if the feature is supported }
If this looks familiar, it's because it's been used in several previous examples in this book. For example, most of the code listings in [Hour 14], "Using Advanced DOM Features," make use of feature sensing to prevent errors in browsers that don't support the W3C DOM.
You don't need to check for every feature before you use it—for example, there's not much point in verifying that the window object exists in most cases. You can also assume that the existence of one feature means others are supported: If getElementById() is supported, chances are the rest of the W3C DOM functions are supported.
Feature sensing is a very reliable method of keeping your JavaScript unobtrusive—if a browser supports the feature, it works, and if the browser doesn't, your script stays out of the way. It's also much easier than trying to keep track of hundreds of different browser versions and what they support.
- By the Way
- Feature sensing is also handy when working with third-party libraries, as discussed in [Hour 8]. You can check for the existence of an object or a function belonging to the library to verify that the library file has been loaded before your script uses its features.
Dealing with Browser Quirks
[wax ka badal]So, if feature sensing is better than browser sensing, why do you still need to know about the navigator object? There's one situation where it still comes in handy, although if you're lucky you won't find yourself in that situation.
As you develop a complex script and test it in multiple browsers, you might run across a situation where your perfectly standard code works as it should in one browser, and fails to work in another. Assuming you've eliminated the possibility of a problem with your script, you've probably run into a browser bug, or a difference in features between browsers at the very least. Here are some tips for this situation:
- Double-check for a bug in your own code. See [Hour 16], "Debugging JavaScript Applications," for debugging tips.
- Search the Web to see if others have run into the same bug. Often you'll find that someone else has already found a workaround.
- Try a different approach to the code, and you might sidestep the bug.
- If the problem is that a feature is missing in one browser, use feature sensing to check for that feature.
- When all else fails, use the navigator object to detect a particular browser and substitute some code that works in that browser. This should be your last resort.
- Did you Know?
- Peter-Paul Koch's QuirksMode, www.quirksmode.org, is a good place to start when you're looking for specific information about browser bugs.
Supporting Non-JavaScript Browsers
[wax ka badal]Some visitors to your site will be using browsers that don't support JavaScript at all. These aren't just a few holdouts using ancient browsers—actually, there are more non-JavaScript browsers than you might think:
- Both Internet Explorer and Firefox include an option to turn off JavaScript, and some users do so. More often, the browser might have been set up by their ISP or employer with JavaScript turned off by default, usually in a misguided attempt to increase security.
- Some corporate firewalls and personal antivirus software block JavaScript.
- Some ad-blocking software mistakenly prevents scripts from working even if they aren't related to advertising.
- More and more mobile phones are coming with web browsers these days, and most of these support little to no JavaScript.
- Some disabled users use special-purpose browsers or text-only browsers that might not support JavaScript.
As you can see, it would be foolish to assume that all of your visitors will support JavaScript. Two techniques you can use to make sure these users can still use the site are discussed in the following sections.
- By the Way
- Search engines are another "browser" that will visit your site frequently, and they usually don't pay any attention to JavaScript. If you want search engines to fully index your site, it's critical that you avoid making JavaScript a requirement to navigate the site.
Using the <noscript> Tag
[wax ka badal]One way to be friendly to non-JavaScript browsers is to use the <noscript> tag. Supported in most modern browsers, this tag displays a message to non-JavaScript browsers. Browsers that support JavaScript ignore the text between the <noscript> tags, whereas others display it. Here is a simple example:
<noscript> This page requires JavaScript. You can either switch to a browser that supports JavaScript, turn your browser's script support on, or switch to the <a href="nojs.html">Non-JavaScript</a> version of this page. </noscript>
Although this works, the trouble is that <noscript> is not consistently supported by all browsers that support JavaScript. An alternative that avoids <noscript> is to send users with JavaScript support to another page. This can be accomplished with a single JavaScript statement:
<script language="JavaScript" type="text/javascript"> window.location="JavaScript.html"; </script>
This script redirects the user to a different page. If the browser doesn't support JavaScript, of course, the script won't be executed, and the rest of the page can display a warning message to explain the situation.
Keeping JavaScript Optional
[wax ka badal]Although you can detect JavaScript browsers and display a message to the rest, the best choice is to simply make your scripts unobtrusive. Use JavaScript to enhance rather than as an essential feature, keep JavaScript in separate files, assign event handlers in the JavaScript file rather than in the HTML, and browsers that don't support JavaScript will simply ignore your script.
In those rare cases where you absolutely need JavaScript—for example, an AJAX application or a JavaScript game—you can warn users that JavaScript is required. However, it's a good idea to offer an alternative JavaScript-free way to use your site, especially if it's an e-commerce or business site that your business relies on. Don't turn away customers with lazy programming.
One place you should definitely not require JavaScript is in the navigation of your site. Although you can create drop-down menus and other fancy navigation tools using JavaScript, they prevent users' non-JavaScript browsers from viewing all of your site's pages. They also prevent search engines from viewing the entire site, compromising your chances of getting search traffic.
- By the Way
- Google's Gmail application (mail.google.com), one of the most well-known uses of AJAX, requires JavaScript for its elegant interface. However, Google offers a Basic HTML View that can be used without JavaScript. This allows them to support older browsers and mobile phones without compromising the user experience for those with modern browsers.
Avoiding Errors
[wax ka badal]If you've made sure JavaScript is only an enhancement to your site, rather than a requirement, those with browsers that don't support JavaScript for whatever reason will still be able to navigate your site. One last thing to worry about: It's possible for JavaScript to cause an error, or confuse these browsers into displaying your page incorrectly.
This is a particular concern with browsers that partially support JavaScript, such as mobile phone browsers. They might interpret a <script> tag and start the script, but might not support the full JavaScript language or DOM. Here are some guidelines for avoiding errors:
- Use a separate JavaScript file for all scripts. This is the best way to guarantee that the browser will ignore your script completely if it does not have JavaScript support.
- Use feature sensing whenever your script tries to use the newer DOM features, such as document.getElementById().
- Test your pages with your browser's JavaScript support turned off. Make sure nothing looks strange, and make sure you can still navigate the site.
- Did you Know?
- The developer's toolbars for Firefox and Internet Explorer include a convenient way to turn off JavaScript for testing. See [Hour 16] for details.
Try It Yourself — Creating an Unobtrusive Script
[wax ka badal]As an example of unobtrusive scripting, you can create a script that adds functionality to a page with JavaScript without compromising its performance in older browsers. In this example, you will create a script that creates graphic check boxes as an alternative to regular check boxes.
- By the Way
- Note: See [Hour 11], "Getting Data with Forms," for the basics of working with forms in JavaScript.
Let's start with the final result: [Figure 15.3] shows this example as it appears in Firefox. The first check box is an ordinary HTML one, and the second is a graphic check box managed by JavaScript.
The graphic check box is just a larger graphic that you can click on to display the checked or unchecked version of the graphic. Although this could just be a simple JavaScript simulation that acts like a check box, it's a bit more sophisticated. Take a look at the HTML for this example in [Listing 15.2].
- Listing 15.2. The HTML File for the Graphic Check box Example
<html> <head> <title>Graphic Checkboxes</title> </head> <body> <h1>Graphic Checkbox Example</h1> <form name="form1"> <p> <input type = "checkbox" name="check1" id="check1"> An ordinary checkbox. </p><p> <input type = "checkbox" name="check2" id="check2"> A graphic checkbox, created with unobtrusive JavaScript. </p> </form> <script language="JavaScript" type="text/javascript" src="checkbox.js"> </script> </body> </html>
If you look closely at the HTML, you'll see that the two check boxes are defined in exactly the same way with the standard <input> tag. Rather than substitute for a check box, this script actually replaces the regular check box with the graphic version. The script for this example is shown in [Listing 15.3].
- Listing 15.3. The JavaScript File for the Graphic Check box Example
function graphicBox(box) { // be unobtrusive if (!document.getElementById) return; // find the object and its parent obj = document.getElementById(box); parentobj = obj.parentNode; // hide the regular checkbox obj.style.visibility = "hidden"; // create the image element and set its onclick event img = document.createElement("IMG"); img.onclick = Toggle; img.src = "unchecked.gif"; // save the checkbox id within the image ID img.id = "img" + box; // display the graphic checkbox parentobj.insertBefore(img,obj); } function Toggle(e) { if (!e) var e=window.event; // find the image ID img = (e.target) ? e.target : e.srcElement; // find the checkbox by removing "img" from the image ID checkid = img.id.substring(3); checkbox = document.getElementById(checkid); // "click" the checkbox checkbox.click(); // display the right image for the clicked or unclicked state if (checkbox.checked) file = "checked.gif"; else file="unchecked.gif"; img.src=file; } //replace the second checkbox with a graphic graphicBox("check2");
This script has three main components:
- The graphicBox() function converts a regular check box to a graphic one. It starts by hiding the existing check box by changing its style.visibility property, and then creates a new image node containing the unchecked.gif graphic and inserts it into the DOM next to the original check box. (These DOM features were described in the previous hour.) It gives the image an id attribute containing the text img plus the check box's id attribute to make it easier to find the check box later.
- The Toggle() function is specified by graphicBox() as the event handler for the new image's onClick event. This function removes img from the image's id attribute to find the id of the real check box. It executes the click() method on the check box, toggling its value. Finally, it changes the image to unchecked.gif or checked.gif depending on the state of the real check box.
- The last line of the script file runs the graphicBox() function to replace the second check box with the id attribute check2.
Using this technique has three important advantages. First, it's an unobtrusive script. The HTML has been kept simple, and browsers that don't support JavaScript will display the ordinary check box. Second, because the real check box is still on the page but hidden, it will work correctly when the form is submitted to a server-side script. Last but not least, you can use it to create any number of graphic check boxes simply by defining regular ones in the HTML file and adding a call to graphicBox() to transform each one.
- By the Way
- See [Hour 19], "Using Graphics and Animation," for details on the image manipulation features used in this example.
To try this example, save the JavaScript file as checkbox.js, and be sure the HTML file is in the same folder. You'll also need two graphics the same size, unchecked.gif and checked.gif, in the same folder. You can download all of the files you need for this example from this book's website.
Summary
[wax ka badal]In this hour, you've learned many guidelines for creating scripts that work in as many browsers as possible, and learned how to avoid errors and headaches when working with different browsers. Most important, you learned how you can use JavaScript while keeping your pages small, efficient, and valid with web standards.
In the next hour, you'll learn about another thing you'll run into frequently when working with more advanced scripts: bugs. [Hour 16] shows you how to avoid common JavaScript errors, and how to use debugging tools and techniques to find and fix errors when they happen.
Q&A
[wax ka badal]Q1: Is it possible to create 100% unobtrusive JavaScript that can enhance a page without causing any trouble for anyone?
A1: Not quite. For example, the unobtrusive script in the Try It Yourself section of this hour is close—it will work in the latest browsers, and the regular check box will display and work fine in even ancient browsers. However, it can still fail if someone with a modern browser has images turned off: The script will hide the check box because JavaScript is supported, but the image won't be there. This is a rare circumstance, but it's an example of how any feature you add can potentially cause a problem for some small percentage of your users.
Q2: Can I detect the user's email address using the navigator object or another technique?
A2: No, there is no reliable way to detect users' email addresses using JavaScript. (If there was, you would get hundreds of advertisements in your mailbox every day from companies that detected your address as you browsed their pages.) You can use a signed script to obtain the user's email address, but this requires the user's permission and only works in some versions of Netscape.
Q3: Are there browsers besides Firefox, Netscape, and Internet Explorer that support JavaScript?
A3: Yes. Opera is a multiplatform browser that supports JavaScript and the W3C DOM. Apple's Safari browser for Macintosh also supports JavaScript. It's always best to support all browsers if you can, and to focus on web standards rather than particular browsers.
Quiz Questions
[wax ka badal]Test your knowledge of unobtrusive scripting by answering the following questions.
1. Which of the following is the best place to put JavaScript code?
- Right in the HTML document
- In a separate JavaScript file
- In a CSS file
2.
Which of the following is something you can't do with JavaScript?
- Send browsers that don't support a feature to a different page
- Send users of Internet Explorer to a different page
- Send users of non-JavaScript browsers to a different page
3.
Which of the following is the best way to define an event handler that works in all modern browsers?
- <body onLoad="MyFunction()">
- window.onload=MyFunction;
- window.attachEvent('load',MyFunction,false);
Quiz Answers
[wax ka badal]1. b. The best place for JavaScript is in a separate JavaScript file.
2. c. You can't use JavaScript to send users of non-JavaScript browsers to a different page because the script won't be executed at all.
3. b. The code window.onload=MyFunction; defines an event handler in all modern browsers. This is better than using an inline event handler as in (a) because it keeps JavaScript out of the HTML document. Option (c) uses the W3C's standard method, but does not work in Internet Explorer.
Exercises
[wax ka badal]If you want to gain more experience creating cross-browser scripts, try the following exercises:
- Add several check boxes to the HTML document in [Listing 15.2], and add the corresponding function calls to the script in [15.3] to replace all of them with graphic check boxes.
- Modify the script in [Listing 15.3] to convert all check boxes with a class value of graphic into graphic check boxes. You can use getElementsByTagName() and then check each item for the right className property.