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 appliance—not 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 standards—essentially treating the standards as
platforms—may 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:
<noscript>
<p>
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>.
</p>
</noscript>
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
//-->
</script>
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 browsers—the latter determined by the
separate document object models—is 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>
<script language="JavaScript1.2" type="text/javascript">
function myFunction( ) {
function statements
}
</script>
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 Detection—the 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 IE—all 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
property—all 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.
|