Chapter 20. Compatibility Techniques
JavaScript, like Java, is one of a new breed of platform-independent languages. That is,
you can develop a program in JavaScript and expect to run it unchanged in a JavaScript-
enabled web browser running on any type of computer with any type of operating system.
Though this is the ideal, we live in an imperfect world and have not yet reached that state
of perfection.
There are, and probably always will be, compatibility problems that JavaScript
programmers must bear in mind. The one fact that we must always remember is that it is
a heterogeneous network out there. Your JavaScript programs may run on three or more
operating systems, using three or more versions of browsers from at least two different
vendors. This can be difficult to keep in mind for those of us who come from the
nonportable past, when programs were developed on a platform-specific basis.
Remember: which platform you develop a program on doesn't matter. It may work fine
on that platform, but the real test is whether it works (or fails gracefully) on all platforms
on which it is used.
The compatibility issues fall into two broad categories: platform-specific, browser-
specific, and version-specific features on one hand; and bugs and language-level
ity of JavaScript
When developing production-quality JavaScript code, testing and knowledge of platform-
ecific, vendor-specific, and version-specific incompatibilities are your chief allies. If
you know, for example, that Netscape 2 on Macintosh platforms always gets the time
wrong by about an hour, you can take steps to deal with this problem. If you know that
Netscape 2 and 3 on Windows platforms do not automatically clear your setting of the
se
Knowledge of existing incompatibilities is crucial to writing compatible code.
incompatibilities, including the incompatibil with non-JavaScript
browsers, on the other. This chapter discusses techniques for coping with compatibility
issues in both of these areas. If you've worked your way through all the previous chapters
in this book, you are probably an expert JavaScript programmer, and you may already be
writing serious JavaScript programs. Don't release those programs on the Internet (or
onto a heterogeneous intranet) before you've read this chapter, though!
20.1 Platform and Browser Compatibility
sp
status line when the mouse moves off a hypertext link, you can provide an appropriate
event handler to explicitly clear the status line. If you know that Internet Explorer 4 and
Netscape 4 support vastly different Dynamic HTML models, you can write pages that u
the appropriate mechanism depending on the browser in use.
Unfortunately, producing a definitive listing of all known vendor, version, and platform
incompatibilities would be an enormous task. It is beyond the scope and mission of this
book, and it has apparently never even been seriously attempted. You may find some
assistance on the Internet, but you will have to rely primarily on your own experience and
testing. Once you have identified an area of incompatibility, however, there are a number
ing sections.
atibilities is to avoid them like the plague. For
t
of basic approaches you can take to coping with it, as described in the follow
20.1.1 The Least-Common-Denominator Approach
One technique for dealing with incomp
example, the Date object is notoriously buggy in Netscape 2. If you want Netscape 2
object ausers to be able to use your programs, you can simply avoid relying on the Date
all.
[1]
[1]
I don't actually recommend doing this. At the time of this writing, Netscape 2 is so far out of date that it is safe to ignore it.
-denominator approach says
tead,
ou can create an equivalent property of your own whenever you open a new window:
newwin = window.open("", "new", "width=500, height=300");
newwin.creator = self;
If you consistently set a creator property for each new window you create, you can rely
on that property instead of the nonportable opener property. (Another alternative, as
we'll see later, is to give up on compatibility with Netscape 2 and require a browser that
supports JavaScript 1.1 or later, as all such browsers support the opener property.)
With this technique, you use only features that are known to work on all your target
ut it
20.1.2 Defensive Coding
code that contains
. For example,
s that
ing with incompatibilities. If you want to
ript that
ted on the
As another example, Netscape 3 and IE 3 both support the
opener property of the
Window object, but Netscape 2 does not. The least-common
ld not use this property if compatibility with Netscape 2 is a goal. Insthat you shou
y
platforms. It doesn't allow you to write cutting-edge programs or push the envelope, b
results in portable, safe programs that can serve many important functions.
With the defensive coding approach to compatibility, you write
platform-independent workarounds for platform-specific incompatibilities
if you set the
status property of a Window object from the onmouseover event handler
to display a custom message in the status line, the status line is cleared when you move
the mouse off the hyperlink, except in Windows versions of Netscape 2 and 3. To correct
for this problem, you could get in the habit of including an onmouseout event handler to
clear the status line. This precaution fixes the bug in current (and future) platform
have it and doesn't do any harm on platforms that don't have the bug.
20.1.3 Feature Testing
Feature testing is a powerful technique for cop
use a feature that may not be supported by all browsers, include code in your sc
tests to see whether that feature is supported. If the desired feature is not suppor
current platform, either do not use it on that platform or provide alternative code that
platforms.
onsider again the opener property. In the least-common-denominator approach, we
simply avoided the use of this property and used an alternative on all platforms. With the
feature-testing approach, we provide the alternative only when the current platform does
rks
the existence of methods. For example, the split( ) method of the String
d like to use
uilt-in method on those platforms that do support it. Thus, our feature-testing
is safe to invoke it
ting is commonly used for performing DHTML effects that are supported only
or are implemented differently in different browsers. For example, if
fects, you can use feature testing
ages) { // If the browser defines an images[] array,
}
// Otherwise, we simply omit the image rollover effect
ure
testing to see which API is supported by the current browser with code like this:
OM API
f (document.all) { // If the IE 4 API is supported,
// do our DHTML using the IE 4 API
}
else if (document.layers) { // If the Netscape 4 API is supported,
// do the DHTML effect (as best we can) using the Netscape 4 API
}
works on all
C
not support opener:
newwin = window.open("", "new", "width=500, height=300");
if (!newwin.opener) newwin.opener = self;
Note how we tested for the existence of the opener property. The same technique wo
to test for
object exists only for JavaScript 1.1 implementations. We can write our own version of
this function that works in all versions of JavaScript, but for efficiency we'
the fast, b
code to split( ) a string might end up looking like this:
if (s.split) // Check if the method exists, without
invoking it
a = s.split(":"); // If it does exist, it
else // Otherwise:
ion a = mysplit(s, ":"); // use our alternative implementat
Feature tes
on some browsers
you are designing a site that includes image rollover ef
with code like this:
if (docu
// we include image rollover code here
ment.im
As another example, suppose we want to work with a dynamically positioned document
element. Different browsers have different APIs for doing this, so we first use feat
if (document.getElementById) { // If the W3C DOM API is supported,
// do our DHTML using the W3C D
}
else i
else { // Otherwise, DHTML is not supported,
// so provide a static alternative to DHTML, if we can
}
Feature testing is well suited to checking for support of large functional areas. You can
API,
s
ence
ed
e
The nice thing about the feature-testing technique is that it results in code that is not tied
to a specific list of browser vendors or browser version numbers. It works with the set of
browsers that exist today and should continue to work with future browsers, whatever
feature sets they implement.
20.1.4 Platform-Specific Workarounds
use it to determine whether a browser supports image rollovers or the W3C DOM
for example. On the other hand, sometimes you may need to work around individual bug
or quirks in a particular browser, and there may be no easy way to test for the exist
of the bug. In this case, you will need to create a platform-specific workaround that is ti
to a particular browser vendor, version, or operating system (or some combination of th
three).
Recall from
Chapter 13 that the navigator property of the Window object provides
information about the vendor and version of the browser and the operating system on
which it is running. You can use this information to insert platform-specific code into
your program.
An example of a platform-specific workaround involves the bgColor property of the
Document object. On Windows and Macintosh platforms, you can set this property at
runtime to change the background color of a document. Unfortunately, when you do this
on Unix versions of Netscape 2 and 3, the color changes but the document contents
temporarily disappear. If you wanted to create a special effect using a changing
background color, you could use the Netscape object to test for Unix platforms and
simply skip the special effect for those platforms. The code could look like this:
// Check whether we're running Netscape 2 or 3 on a Unix platform
var nobg = (parseInt(navigator.appVersion) < 4) && // Version
// If we're not, then go ahead and animate the page background color
ommon to use " client-sniffer" code
tform is, based (typically) on the properties of the
and it sets variables that
rse the properties of navigator
for each platform-specific bit of code you write; you can simply use the variables set by
(navigator.appName.indexOf("Netscape") != -1) && // Vendor
(navigator.appVersion.indexOf("X11") != -1); // OS
if (!nobg) animate_bg_color( );
When writing platform-specific workarounds, it is c
to determine what the current pla
navigator object. You run your client-sniffer code once,
current platform. Then you don't have to repadescribe the
the sniffer code. A simple sniffer that may be sufficient for many purposes might look
like this:
var browserVersion = parseInt(navigator.appVersion);
var isNetscape = navigator.appName.indexOf("Netscape") != -1;
var isIE = navigator.appName.indexOf("Microsoft") != -1;
var agent = navigator.userAgent.toLowerCase( );
var isWindows = agent.indexOf("win") != -1;
var isMac = agent.indexOf("mac") != -1;
var isUnix = agent.indexOf("X11") != -1;
With variables like these defined, you might write code like the following:
if (isNetscape && browserVersion < 4 && isUnix) {
r/browser_type.html
// Work around a bug in Netscape 3 on Unix platforms here
}
A variety of prewritten client sniffers are available on the Internet. You can find a
thorough one (along with a helpful discussion of its use) at
.
Server-Side Scripts
patibility is possible if your web application
se of server-side scripts, such as CGI scripts or server-side JavaScript. A
rogram on the server side can inspect the User-Agent field of the HTTP request header,
which allows it to determine exactly what browser the user is running. With this
s that do not require JavaScript at all. An
important drawback to this approach is that a server-side script cannot detect when a user
has disabled JavaScript support in her browser.
d
ring any incompatibility is, how important is
smetic, affects a browser or platform that is not
r affects only an out-of-date version of a browser, you might simply decide
lem and let the users affected by it cope with it on their own.
is
20.1.5 Compatibility Through
Another platform-specific approach to com
includes the u
p
information, the program can generate customized JavaScript code that is known to work
correctly on that browser. Or, if the server-side script detects that the user's browser does
not support JavaScript, it can generate web page
Note that the topics of CGI programming and server-side scripting in general are beyon
the scope of this book.
20.1.6 Ignore the Problem
An important question to ask when conside
it? If the incompatibility is minor or co
widely used, o
to ignore the prob
For example, earlier I suggested defining an
onmouseout event handler to correct for the
fact that Netscape 2 and 3 for Windows do not correctly clear the status line.
Netscape 2, so thUnfortunately, the
onmouseout event handler is not supported in