Section 13.6. Client-Side Compatibility


13.6. Client-Side Compatibility

The web browser is a universal platform for hosting applications, and JavaScript is the language in which those applications are developed. Fortunately, the JavaScript language is standardized and well-supported: all modern web browsers support ECMAScript v3. The same can not be said for the platform itself. All web browsers display HTML, of course, but they differ in their support for other standards such as CSS (Cascading Style Sheets) and the DOM. And although all modern browsers include a compliant JavaScript interpreter, they differ in the APIs they make available to client-side JavaScript code.

Compatibility issues are simply an unpleasant fact of life for client-side JavaScript programmers. The JavaScript code you write and deploy may be run in various versions of various browsers running on various operating systems. Consider the permutations of popular operating systems and browsers: Internet Explorer on Windows and Mac OS;[*] Firefox on Windows, Mac OS, and Linux; Safari on Mac OS; and Opera on Windows, Mac OS, and Linux. If you want to support the current version of each browser plus the previous two versions, multiply these nine browser/OS pairs by three, for a total of 27 browser/version/OS combinations. The only way to be absolutely sure that your web application runs on all 27 combinations is to test it in each. This is a daunting task, and in practice, the testing is often done by the users after the application is deployed!

[*] IE for Mac is being phased out, which is a blessing because it is substantially different from IE for Windows.

Before you reach the testing phase of application development, you must write the code. When programming in JavaScript, knowledge of the incompatibilities among browsers is crucial for creating compatible code. 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 to my knowledge, no comprehensive client-side JavaScript test suite has ever been developed. You can find browser compatibility information online, and here are two sites that I have found useful:


http://www.quirksmode.org/dom/

This is freelance web developer Peter-Paul Koch's web site. His DOM compatibility tables show the compatibility of various browsers with the W3C DOM.


http://webdevout.net/browser_support.php

This site by David Hammond is similar to quirksmode.org, but its compatibility tables are more comprehensive and (at the time of this writing) somewhat more up-to-date. In addition to DOM compatibility, it also rates browser compliance with the HTML, CSS, and ECMAScript standards.

Awareness of incompatibilities is only the first step, of course. The subsections that follow demonstrate techniques you can use to work around the incompatibilities you encounter.

13.6.1. The History of Incompatibility

Client-side JavaScript programming has always been about coping with incompatibility. Knowing the history provides some useful context. The early days of web programming were marked by the "browser wars" between Netscape and Microsoft. This was an intense burst of development, in often incompatible directions, of the browser environment and client-side JavaScript APIs. Incompatibility problems were at their worst at this point, and some web sites simply gave up and told their visitors which browser they needed to use to access the site.

The browser wars ended, with Microsoft holding a dominant market share, and web standards, such as the DOM and CSS, started to take hold. A period of stability (or stagnation) followed while the Netscape browser slowly morphed into the Firefox browser and Microsoft made a few incremental improvements to its browser. Standards support in both browsers was good, or at least good enough for compatible web applications to be written.

At the time of this writing, we seem to be at the start of another burst of browser innovation. For example, all major browsers now support scripted HTTP requests, which form the cornerstone of the new Ajax web application architecture (see Chapter 20). Microsoft is working on Internet Explorer 7, which will address a number of long-standing security and CSS compatibility issues. IE 7 will have many user-visible changes but will not, apparently, break new ground for web developers. Other browsers are breaking new ground, however. For example, Safari and Firefox support a <canvas> tag for scripted client-side graphics (see Chapter 22). A consortium of browser vendors (with the notable absence of Microsoft) known as WHATWG (whatwg.org) is working to standardize the <canvas> tag and many other extensions to HTML and the DOM.

13.6.2. A Word about "Modern Browsers"

Client-side JavaScript is a moving target, especially if we're indeed entering a period of rapid evolution. For this reason, I shy away in this book from making narrow statements about particular versions of particular browsers. Any such claims are likely to be outdated before I can write a new edition of the book. A printed book like this simply cannot be updated as often as necessary to provide a useful guide to the compatibility issues that affect the current crop of browsers.

You'll find, therefore, that I often hedge my statements with purposely vague language like "all modern browsers" (or sometimes "all modern browsers except IE"). At the time of this writing, the loose set of "modern browsers" includes: Firefox 1.0, Firefox 1.5, IE 5.5, IE 6.0, Safari 2.0, Opera 8, and Opera 8.5. This is not a guarantee that every statement in this book about "modern browsers" is true for each of these specific browsers. However, it allows you to know what browsers were current technology when this book was written.

13.6.3. Feature Testing

Feature testing (sometimes called capability testing) is a powerful technique for coping with incompatibilities. If you want to use a feature or capability that may not be supported by all browsers, include code in your script that tests to see whether that feature is supported. If the desired feature is not supported on the current platform, either do not use it on that platform or provide alternative code that works on all platforms.

You'll see feature testing again and again in the chapters that follow. In Chapter 17, for example, there is code that looks like this:

 if (element.addEventListener) { // Test for this W3C method before using it     element.addEventListener("keydown", handler, false);     element.addEventListener("keypress", handler, false); } else if (element.attachEvent) { // Test for this IE method before using it     element.attachEvent("onkeydown", handler);     element.attachEvent("onkeypress", handler); } else {  // Otherwise, fall back on a universally supported technique     element.onkeydown = element.onkeypress = handler; } 

Chapter 20 describes yet another approach to feature testing: keep trying alternatives until you find one that does not throw an exception! And, when you find an alternative that works, remember it for future use. Here is a preview of code from Example 20-1:

 // This is a list of XMLHttpRequest creation functions to try HTTP._factories = [     function( ) { return new XMLHttpRequest( ); },     function( ) { return new ActiveXObject("Msxml2.XMLHTTP"); },     function( ) { return new ActiveXObject("Microsoft.XMLHTTP"); } ]; // When we find a factory that works, store it here HTTP._factory = null; // Create and return a new XMLHttpRequest object. // // The first time we're called, try the list of factory functions until // we find one that returns a nonnull value and does not throw an // exception. Once we find a working factory, remember it for later use. HTTP.newRequest = function( ) { /* fuction body omitted */ } 

A common, but outdated, example of feature testing that you may still encounter in existing code is used to determine which DOM a browser supports. It often occurs in DHTML code and usually looks something like this:

 if (document.getElementById) {  // If the W3C DOM API is supported,     // do our DHTML using the W3C DOM API } else if (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 } else {                          // Otherwise, DHTML is not supported,     // so provide a static alternative to DHTML } 

Code like this is outdated because almost all browsers deployed today support the W3C DOM and its document.getElementById( ) function.

The important 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. Note, however, that it requires browser vendors not to define a property or method unless that property or method is fully functional. If Microsoft were to define an addEventHandler( ) method that only partially implemented the W3C specification, it would break a lot of code that uses feature testing before calling addEventHandler( ).

The document.all property shown in this example deserves a special mention here. The document.all[] array was introduced by Microsoft in IE 4. It allowed JavaScript code to refer to all elements of a document and ushered in a new era of client-side programming. It was never standardized and was superseded by document.getElementById( ). It is still used in existing code and has often been used (incorrectly) to determine whether a script is running in IE with code like this:

 if (document.all) {     // We're running in IE } else {     // We're in some other browser } 

Because there is still a lot of extant code that uses document.all, the Firefox browser has added support for it so that Firefox can work with sites that were previously IE-dependent. Because the presence of the all property is often used for browser detection, Firefox pretends that it does not support the property. So even though Firefox does support document.all, the if statement in the following script behaves as if the all property does not exist, and the script displays a dialog box containing the text "Firefox":

 if (document.all) alert("IE"); else alert("Firefox"); 

This example illustrates that the feature-testing approach does not work if the browser actively lies to you! It also shows that web developers are not the only ones plagued by compatibility issues. Browser vendors must also go through contortions for compatibility.

13.6.4. Browser Testing

Feature testing is well suited to checking for support of large functional areas. You can use it to determine whether a browser supports the W3C event-handling model or the IE event-handling model, for example. On the other hand, sometimes you may need to work around individual bugs or quirks in a particular browser, and there may be no easy way to test for the existence of the bug. In this case, you need to create a platform-specific workaround that is tied to a particular browser vendor, version, or operating system (or some combination of the three).

The way to do this in client-side JavaScript is with the Navigator object, which you'll learn about in Chapter 14. Code that determines the vendor and version of the current browser is often called a browser sniffer or a client sniffer. A simple example is shown in Example 14-3. Client sniffing was a common client-side programming technique in the early days of the Web when the Netscape and IE platforms were incompatible and diverging. Now that the compatibility situation has stabilized, client sniffing has fallen out of favor and should be used only when absolutely necessary.

Note that client sniffing can be done on the server side as well, with the web server choosing what JavaScript code to send based on how the browser identifies itself in its User-Agent header.

13.6.5. Conditional Comments in Internet Explorer

In practice, you'll find that many of the incompatibilities in client-side JavaScript programming turn out to be IE-specific. That is, you must write code in one way for IE and in another way for all other browsers. Although you should normally avoid browser-specific extensions that are not likely to be standardized, IE supports conditional comments in both HTML and JavaScript code that can be useful.

Here is what conditional comments in HTML look like. Notice the tricks played with the closing delimiter of HTML comments:

 <!--[if IE]> This content is actually inside an HTML comment. It will only be displayed in IE. <![endif]--> <!--[if gte IE 6]> This content will only be displayed by IE 6 and later. <![endif]--> <!--[if !IE]> <--> This is normal HTML content, but IE will not display it because of the comment above and the comment below. <!--> <![endif]--> This is normal content, displayed by all browsers. 

Conditional comments are also supported by IE's JavaScript interpreter, and C and C++ programmers may find them similar to the #ifdef/#endif functionality of the C preprocessor. A JavaScript conditional comment in IE begins with the text /*@cc_on and ends with the text @*/. (The cc in cc_on stands for conditional compilation.) The following conditional comment includes code that is executed only in IE:

 /*@cc_on   @if (@_jscript)     // This code is inside a JS comment but is executed in IE.     alert("In IE");   @end   @*/ 

Inside a conditional comment, the keywords @if, @else, and @end delimit the code that is to be conditionally executed by IE's JavaScript interpreter. Most of the time, you need only the simple conditional shown above: @if (@_jscript). JScript is Microsoft's name for its JavaScript interpreter, and the @_jscript variable is always true in IE.

With clever interleaving of conditional comments and regular JavaScript comments, you can set up one block of code to run in IE and a different block to run in all other browsers:

 /*@cc_on   @if (@_jscript)     // This code is inside a conditional comment, which is also a     // regular JavaScript comment. IE runs it but other browsers ignore it.     alert('You are using Internet Explorer);   @else*/     // This code is no longer inside a JavaScript comment, but is still     // inside the IE conditional comment.  This means that all browsers     // except IE will run this code.     alert('You are not using Internet Explorer'); /*@end   @*/ 

Conditional comments, in both their HTML and JavaScript forms, are completely nonstandard. They are sometimes a useful way to achieve compatibility with IE, however.




JavaScript. The Definitive Guide
JavaScript: The Definitive Guide
ISBN: 0596101996
EAN: 2147483647
Year: 2004
Pages: 767

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net