5.0 Introduction

Perhaps the greatest challenge that faces any web author who needs scripting or Dynamic HTML features embedded within content is how to select features that work with the widest set of browsers for the target audience. It wasn't too many years ago that the main concerns about browser versions centered around support for "new" HTML features such as tables and frames. The situation is far more complex today. Despite claims of compatibility with industry standards, each browser implements some features in a peculiar way, may offer its vision of proposed standards, or may include proprietary features never intended for the standards track.

The most dramatic changes to browser functionality from version to version tend to be in two areas: the core JavaScript language (covered in Chapter 1 through Chapter 4) and the document object model (the "things" you manipulate on the page using the JavaScript vocabulary). Features you commonly see in modern web pages, such as images that change color or hue when you roll the cursor over them, were not possible in the earliest scriptable browsers. Images were not yet treated as objects in the DOM, thus preventing scripts from changing the property that points to a different .gif or .jpg file for each color. Even powers that are not evident to the user, such as scripting language data types, evolve with each new browser generation. Scripting powers that an experienced programmer might assume had been part of JavaScript from the first outing, such as an array data structure or switch statements, were not always in the language. A genuine hazard today is if you learn scripting and DHTML in the context of the latest generation of browsers, you may be very surprised (and frustrated) by how much doesn't work in browsers from one or two previous generations.

Complicating the issue is the fact that just because a new generation of web browser is available to the world doesn't mean that the world's user base rushes to adopt it. The cost of upgrading an organization-wide deployment of web browser software may be too high to let employees keep pace with the available software. At the same end of the scale, oddly enough, is the consumer who would rather use a stable, reliable browser for years as if it were an appliancenot something that is upgraded every 12 to 18 months. It's all too easy for the web-literate to get caught up in the latest pre-release browser version frenzy, failing to realize that web server logs won't show the audience reaching a critical mass of that new browser version for as much as one year after its release.

These and other factors conspire to fragment the installed base of browsers in the real world. As a web application author, your task is to balance the desire to spiff up your content with DHTML features against the trouble of making sure the content degrades well on less-capable browsers. Part of achieving this balance is determining how maintainable your content should be. Sure, in an ideal world, you might have many versions of a given page, each optimized for a combination of browser brand, browser version, and operating system. But unless you have very sophisticated content management tools, a single text change to a page may become an unthinkable nightmare to deploy. In truth, the more palatable ideal world lets one HTML file (or server routine under PHP, ASP, JSP, and others) handle browser- and operating system-specific idiosyncrasies. That's what browser feature detection and scripting are all about.

Unfortunately, there are no hard and fast rules to follow when it comes to handling browser detection. Each combination of content and target audience has its own compatibility requirements. It's helpful to know this ahead of time, because you can start thinking about the level of browser detection you need to deploy for your content. In fact, it's one of the first things I address when embarking on a new project.

5.0.1 Developing a Browser Strategy

An approach I frequently recommend is to start with a mock-up of the art and content for related pages. Next, visualize the ideal user interaction that adds value to the content. For example: would site navigation be faster with pop-up submenus associated with main menu icons? Do you want to offer customized visual settings that are invoked automatically when a user accesses the site next time? Would it be more fun and convenient for users to build components of their online order by dragging icons representing features or modules?

With your wish list in hand, it's time to figure out what browser versions can support those features, and then map that support to the profiles of users you expect for the site. You may want to have all the fancy user interface features available for users of only the most recently released browsers and shuttle all others to a simpler presentation. A lot of scriptable and DHTML features can be added to a page such that the same HTML file serves both older and newer browsers, with users of new browsers getting the benefit of the added features.

To make any these grand ideas work, you must include browser or feature detection scripts in your document. Such detection can be as simple as creating separate script-processing paths in the same document for Navigator and Internet Explorer. Your designs may call for two or more HTML document paths through your web site, depending not only on various levels of scriptability but also on whether the browser is scriptable at all. You might even have your default page act as a filter for the browser flavors you are prepared to handle.

5.0.2 When There Is No JavaScript

It's not unusual for a newcomer to client-side scripting to wonder how a script might detect the absence of JavaScript. Only after a bit of thought do they realize the ridiculous proposition of using JavaScript for decision-making when the browser completely ignores all scripts.

A user won't have JavaScript available for one of two reasons one by force, one by choice. The most common reason is that the browser knows nothing about JavaScript. This isn't limited only to nongraphical browsers such as Lynx or special-purpose browsers for disabled users. An increasing number of portable wireless devices use browsers endowed with little or none of the scripting support found in full-fledged browsers.

Regardless of the latest browser bells and whistles, or the "preferred" way to apply certain content constructs, many thousands of web pages on the Net use techniques long gone from the standards documents. Web browser makers bear the burden of this "ancient" baggage, as their browsers (with rare exception) continue to be backward-compatible with earlier technologies. Unfortunately, this continued support can lead casual page authors to believe that the old ways are just fine, so they believe they have little incentive to use the latest techniques. Conversely, a tuned-in content author who blindly follows standardsessentially treating the standards as platformsmay be even more foolhardy because browser makers haven't caught up with the standards or have implemented them oddly in the early development stages.

The second reason is that for personal or MIS policy reasons, JavaScript is turned off in a browser that is otherwise capable of JavaScript. When scripting is turned off in a scriptable browser, any HTML content contained by the <noscript> tag pair is rendered by the browser. This is where you might include a message that alerts users about what they're missing:

If you are able to turn on JavaScript in your browsers, you will enjoy 
convenient shortcuts to speed your site navigation. To learn how to enable 
JavaScript for your browser, click the link for your browser: 
<a href="jsiewin.html">Internet Explorer for Windows</a>, 
<a href="jsiemac.html">Internet Explorer for Macintosh</a>, 
<a href="jsnetscape.html">Netscape Navigator</a>.

Users of nonscriptable browsers will usually see the same message because the browsers ignore the <noscript> tags and treat the content as untagged body content. With a little server programming, you can help the visitor even more. By analyzing the HTTP USERAGENT string arriving with the page request, the server can examine the browser and operating system type, and thus provide a single link in the <noscript> tag to the script-enabling instructions tailored for that browser class. Not all visitors know (or care) which browser brand or version they're using. A little extra server programming (if you have access to it for your web hosting) can simplify life for nontechnical visitors.

5.0.3 Masking Scripts from Nonscriptable Browsers

Even though nonscriptable browsers ignore the <script> and </script> tags, they don't know to ignore all of the code that goes between those tags. Unless instructed otherwise, such browsers tend to render script statements as if they were body text. To prevent the display of scripts, you must wrap script statements with HTML comment tags:

<script language="JavaScript">
script statements go here

The start of the HTML comment (<!--) is straightforward. But because the end-comment tag (-->) causes a syntax error in scriptable browsers, a JavaScript comment symbol (//) must precede the end-comment tag. If your page might be viewed by nonscriptable browsers, each <script> tag pair should include these HTML comment tags. Be aware, however, that some older, "brain-dead" browsers (used by an ever-shrinking population of users who upgrade browsers) might not even recognize these valid HTML comment symbols, and will render the script statements no matter what you do.

This masking technique simply prevents page rendering on applicable browsers. This is not a way to prevent inquisitive visitors from viewing the source code of your HTML or scripts. And before you ask, there is no sure-fire way to prevent someone from seeing your client-side scripts. While numerous ways exist to obfuscate your code, a determined visitor will be able to view your scripts one way or another.

5.0.4 Detecting the JavaScript Version

A somewhat imprecise way of providing multiple levels of functionality in a single page is possible by letting scripts branch based on the version of JavaScript built into the browser. This strategy is called browser detection; it was practical in the early days of scripting when increments in the scripting language version were more closely tied to specific browser versions from the only two scriptable browsers: Internet Explorer and Netscape Navigator. For example, JavaScript 1.2 was the language deployed in Navigator 4 and Internet Explorer 4.

Since then, the correlation between JavaScript version number and scriptable features of browsersthe latter determined by the separate document object modelsis too loose to be useful. I no longer recommend language version branching. But, because a lot of legacy code deployed on the Web demonstrates this technique, I present a brief discussion of how it works.

Just like HTML, scripts load into the browser in source code order (i.e., from top to bottom). If the browser encounters more than one function of the same name, the last one to be read overrides all others that appear earlier in the document. But the browser recognizes <script> tags only for the JavaScript language versions it knows about. For example, consider the following parallel sets of tags:

<script language="JavaScript" type="text/javascript">
function myFunction( ) {
    function statements
<script language="JavaScript1.2" type="text/javascript">
function myFunction( ) {
    function statements

A browser that knows only JavaScript 1.0 or 1.1 keeps the first definition of myFunction( ) in memory ready to be invoked by any event handler or script statement. A browser that knows JavaScript 1.2 (or later) loads the first definition into memory as the page loads, but the function is immediately overwritten in memory by the second definition. Only the second function runs when invoked by an event handler elsewhere in the document.

5.0.5 Object Detectionthe Way to Go

Using browser brand, version, or operating system detection assumes that you know for certain which browser versions support a particular document object, property, or method. With so many scriptable browsers prowling the Web these days, it is impossible to know which current or future subversion of each browser supports the object model features you need. This is where a technique known as object detection picks up the slack. As demonstrated in Recipe 5.6 and Recipe 5.7, your scripts can make sure the browser supports a new or limited object model feature before using that feature.

Use object detection wisely. Do not assume that because a browser supports one feature of some other browser that all other features of that other browser are supported. For example, it is an unfortunately common practice to assume that just because a browser supports the document.all collection, the browser is Internet Explorer 4 or later. If you are familiar with that browser class in the Windows environment, you're probably aware of a wide range of IE DOM features. But some of those features are not available in IE 4 or later for other operating systems, nor in the Opera browser set to behave like IEall of which support the document.all collection. On the other hand, you don't need to be a JavaScript guru to know that support for document.all universally equates with support for the document.all.length propertyall object collections have a length property.

Deploying object detection intelligently requires a good source of language- and object-compatibility ratings. The latest edition of Dynamic HTML: The Definitive Reference (O'Reilly) is tailored for this task.

5.0.6 Setting Global Variables

How often your scripts need to perform the actual browser or object detection depends a lot on how large your scripts are and how often those scripts need to differentiate among support profiles for browsers. Most browser detection occurs via the navigator object, sometimes involving compound detection statements (e.g., you're looking for a particular browser brand and version). Because browser detection is most often used to branch script execution within an if construction, it is generally more convenient to establish one or more global variables at the start of your script to be used as flags later on. Let the assignment statements perform the examination and assign true or false Boolean values to the global(s). Then use the global variable(s) as expressions within your branching if conditions:

var isMacOS = (navigator.userAgent.indexOf("Mac") != -1);
if (isMacOS) {
    Macintosh-specific scripts here
} else {
    Other scripts here

You can do the same for object detection (and reduce excessive expression evaluation throughout your scripts):

var isW3C = (document.getElementById) ? true : false;

After some experience, you'll get to know the kinds of branching a particular job requires. Assigning the browser global variables at the start of your scripts will become second nature to you.

5.0.7 DHTML and Accessibility

Many countries have enacted laws that require employers and organizations open to the public to provide site access to employees, customers, and visitors who have a variety of disabilities. It's not uncommon for such users to visit web pages with browsers that permit navigation exclusively via keyboard or render content through speech synthesis. Implementing an application that relies solely on DHTML techniques to convey its content may place such content in violation of these laws. For information about the U.S. law covering this topic, visit http://www.section508.gov.

A related issue is how accessible the content is to search engine spiders and bots that troll the Web to build their databases. These services tend to follow HTML links found on a page, but do not execute scripts. Thus, they see only explicit HTML content as delivered by the web server. If all links from the home page activate only through script control, the search engines won't get past your site's lobby.