Browser Detection versus Object Detection July 2, 2007
Javascript: Things you should know
Use object detection instead of browser detection
Note: This is part I of a "Javascript: Things you should know" series. I assume readers have an understanding of the core language. I try to cover quirks that are important but aren’t covered in text books. The next entry will be quirks with the javascript switch statement.
Use object detection instead of substring detection to determine browser support of your code. Browser detection involves using navigator.userAgent. There are several reasons why you shouldn’t use browser detection.
- Browsers lie about who they are.
- You may filter out browsers that support your code or fail to filter out browsers that don’t support your code..
- Browser detection isn’t future proof: can’t future proof your code against new browsers.
Instead, use object detection: test to see if your browser supports the object you want to manipulate. If the browser supports your objects, yay! You don’t need to know the name of the browser or version number, just whether or not it will support your code.
The most commonly used object detection to check to see if a browser supports the DOM is:
var supportsDOM = document.createElement && document.getElementsByTagName;
This object detection does not mean you can use any object. It simply lets me know whether you should even try implementing your javascript in that particular browser. While the above is a good start, you should still do object detection before assuming browser support.
if(supportsDOM){
var resolution = window.devicePixelRatio;
alert(resolution);
}
At the time of this writing, the only browser that supports the devicePixelRatio property is Safari. See Targeting Safari 3.0 with CSS and Javascript. Safari will return "1", whereas all other browsers will return "undefined". Basically, just because a browser supports the DOM, it does not mean that it supports every object, property and method of the DOM equally, and that it doesn’t have it’s own propietary methods. Once you’ve determined that your browser supports the DOM, you still have to test for method and property support before using it.
if(obj.addEventListener) {
//standards code
}
else if(obj.attachEvent) {
//proprietary code
}
A prime example is IE’s failure to support the WC3 standard addEventListener. Microsoft has it’s own event handling model, supporting attachEvent instead. When performing bject detection, always test for standards compliant methods before proprietary support. IE7 does not support addEventListener. IE8, or whatever the next version is, may support addEventListener and will continue to support attachEvent for backwards compatibility reasons. When IE finally supports the WC3 standard, putting your object detection in this order will ensure that browsers that support standards, whether or not they also support proprietary methods, will use the standard.
Exceptions to the use oject detection not browser detection rule
If you are still supporting IE 5.2 for the Mac, you may want to use browser detection to exclude it. Mac IE 5.2 returns true for if(document.createElement && document.getElementsByTagName), but crashes when it encounters advanced scripts. See Mac IE Hacks.
If you are actually trying to determine which browser is using for some non-javascript reason, such as maintaining statistics on visitors, then it makes sense to use browser detection.
Note: Apple has a good article on object detection versus browser detection.






I am on a panel at
You’re quite right to say that IE5 on the Mac supports some functionality tests, but fails when required to perform more advanced tasks.
I found a good way to filter out IE5 on the Mac from other browsers.
If you test for the existance of window.Error, IE5 (Mac) will fail but all the other, more recent, browsers will pass.
Strangely, my version of IE7 seems to actually support both addEventListener AND attachEvent, which breaks this conditional statement:
add.event = function( obj, strEvent, fnHandler, allowBubbling )
{
if ( obj.addEventListener )
{
obj.addEventListener( strEvent, fnHandler, allowBubbling ); // Works in IE7 on its own
return true;
}
else if ( obj.attachEvent )
{
obj.attachEvent( ‘on’ + strEvent, fnHandle ); // Overrides the above listener!
return true;
}
I don’t get it — is it my fault for not returning properly? Could it be anything to do with the try() block I wrapped the detection block in? If I remove the attachEvent detection, IE7 seems to work with aEL, which caught me by surprise. But then it’s ruined because it still obeys attachEvent, despite addEventListener being the first case. And I end up with THREE triggers for a single window load event — but that might be due to something else I read about…