- Cross-Browser Issues
- Detecting the User's Browser
- Creating a Custom Object Front End
Detecting the User's Browser
The heart and soul of any cross-browser script, function, or code is browser detection. Only when you know what browser the user is running (and, depending on the code or feature you're using, the browser version and the user's operating system) can you redirect the user to run whatever code works best with his browser. There are two types of detection: browser version detection and object detection.
Using Browser Version Detection
Browser version detection involves examining information returned by the user's browser: its name, its version number, its operating system, and so on. All of this is returned by the Navigator object. A "browser sniffer" script examines various Navigator object properties and sets a number of Boolean variables based on the Navigator values.
The most commonly used of these variables are those related to the browser name and version. For the browser name, the sniffer tracks the following Boolean variables:
For DHTML, your real interest lies not just in the browser name, but in the name and version number. For that, the sniffer includes the following Boolean variables:
Given these Booleans, your browser detection code might look something like this:
if (its_ie5plus || its_ns6plus) { W3C DOM-compliant code goes here } else if (its_ie4) { DHTML DOM-compliant code goes here } else if (its_ns4) { LDOM-compliant code goes here } else { alert("Sorry, you browser doesn't support DHTML.") return }
There are two important things to note about this code:
The detection always starts with the latest browser version and works its way down through earlier versions.
The first if() testthat is, the one that checks for the latest versionsalways uses the "plus" variable (such as its_ie5plus and its_ns6plus).
The latter means that your if() test will return true not only for what is now the latest version of the browser, but also for any future versions that come along. The assumption here is that future versions of the browser will be backward-compatible, so the code you branch to will still work in any future version.
There are some risks to this approach, particularly if a future version is released that's not backward-compatible. The most famous recent example of this is Netscape 6, which has no support for the DHTML features of Netscape 4. This meant that thousands of scripts that branched based on the equivalent of if (its_ns4plus) simply didn't work in Netscape 6. That's been a hassle, for sure, but the upside is that it's forcing lots of sites to learn the W3C DOM and to start using standards instead of (or, more likely, in addition to) Netscape 4's proprietary object model.
Using Object Detection
In the previous section, you saw that a potential flaw with a browser-detection scheme is that is might be foiled by a future browser version that's incompatible with whatever code the script branches to. A second problem with browser detection is that it can easily miss a browser. For example, if your goal is to implement a DHTML feature, then you want to check for Internet Explorer 4, Netscape 4, Internet Explorer 5 and up, and Netscape 6 and up. But what about the Opera 5 and Konqueror browsers, which also support some DHTML? Sure, you can add them to your branching code, but do you really want to create separate code for browsers with miniscule market share? And what if a new browser comes out that supports the W3C DOM (or whatever)? If you want to support it, you need to change your branching code in all your pages.
For these reasons, it's best to avoid browser detection wherever possible. For most uses, a much better approach is object detection, which tests to see whether the browser supports a particular object. If the browser does support it, then you can branch to code that uses the object, safe in the knowledge that the browser (no matter what its name or version) will be able to run it.
For example, when Netscape introduced the Image object, it added a property named images to the Document object. This property returned an array consisting of all the document's images. If you want to use the images object in your code (say, to do a mouseover), you could do something this:
if (its_ns3plus) { document.images[0].src = "some_picture.gif" }
But the images object is also supported by Internet Explorer 4 and later, as well as many other browsers. Rather than populating your if() expression with a great many OR conditions, you could simply do this:
if (document.images) { document.images[0].src = "some_picture.gif" }
If the browser supports the images object, the if() condition returns a reference to the object, which if() sees as true, so the code executes. If the browser doesn't support the object, the condition returns null or undefined, both of which are interpreted by if() as false.
This approach also works with object methods. For example, suppose you want to use the W3C DOM's createElement() method, but you want to run it only if the browser supports it. Rather than checking for Internet Explorer 5+ or Netscape 6+, do this:
if (document.createElement) { document.createElement("div") }
Notice that the text expression includes the method's parent object and that it doesn't include the method's parentheses.
For DHTML, you can use the following objects and methods for your detection code:
The W3C DOM (cross-browser)The key here is usually the document.getElementById() method, particularly if your code needs to do only typical cross-browser things: reference an object and then manipulate its styles or other attributes.
The W3C DOM (advanced)If you're doing more advanced W3C DOM work such as creating, replacing, and deleting nodes, then you should check support for the document.createElement() method. If a browser supports this method, it will almost certainly support other standard element- and node-related methods.
The DHTML DOMFor the Internet Explorer 4 object model, the entry point is the document.all object, so that's what you need to detect.
The LDOMFor the Netscape 4 object model, the starting point is the document.layers object, so you need to detect that.
In general, then, your cross-browser DHTML object detection code will use the following generic structure:
if (document.getElementById) { W3C DOM-compliant code goes here } else if (document.all) { DHTML DOM-compliant code goes here } else if (document.layers) { LDOM-compliant code goes here } else { alert("Sorry, you browser doesn't support DHTML.") return }
I also updated by browser sniffer script with a dhtml_ok Boolean variable that is set to true if the browser supports at least one of the three DOMs:
if (document.getElementById || document.all || document.layers) { dhtml_ok = true }