Javascript Browser Detection Revisited
You’ve all seen them before. Javascript browser detection scripts. There are extremely large and ugly ones out there, ignoring the fact that browser detection in itself is an ugly thing having to resolve to. Our suggestion is based on not trusting the user agent string delivered by the browser. Instead we use a combination of object detection and bad voodoo to be 100% sure what browser and what version is served. Updated for IE7!
Do we really need this?
Hopefully not. In most circumstances you can secure yourself from doing stuff to a browser that it doesnt support, simply by checking if method X or object Y is available before you use it. However, the better you get at scripting, and the more crossbrowser compatibility you have to have, the more boundaries get touched or crossed. You will end up with some stupid differences, like IE’s different implementation of what mousebutton was pressed, or Gecko firing a mouseover event when the mouse wasn’t actually moved, but the position of the element below it was.
So we agree that browser detection is only for far-out stuff, and it’s still ugly. But sometimes you have do to what you can to get the job done. Now, especially when writing stuff that pushes the limits of browser capability, you will encounter people that think they are clever with their browser setup. People writing all sorts of wierd stuff in their user agent string, or just browsers like Opera 8, that had to fake being Internet Explorer because MS was deliberately sending out wrong styles for non-IE browsers on MSN.
If the user agent string can’t be trusted, we need to go deeper. So we decided to use object detection, and for IE a little spicy technique called Conditional Compilation, something only available in JScript.
The Code
function detectBrowser() {
var BO = new Object();
BO["ie"] = false /*@cc_on || true @*/;
BO["ie4"] = BO["ie"] && (document.getElementById == null);
BO["ie5"] = BO["ie"] && (document.namespaces == null) && (!BO["ie4"]);
BO["ie6"] = BO["ie"] && (document.implementation != null) && (document.implementation.hasFeature != null);
BO["ie55"] = BO["ie"] && (document.namespaces != null) && (!BO["ie6"]);
/*@cc_on
BO["ie7"] = @_jscript_version == '5.7';
@*/
BO["ns4"] = !BO["ie"] && (document.layers != null) && (window.confirm != null) && (document.createElement == null);
BO["opera"] = (self.opera != null);
BO["gecko"] = (document.getBoxObjectFor != null);
BO["khtml"] = (navigator.vendor == "KDE");
BO["konq"] = ((navigator.vendor == 'KDE') || (document.childNodes) && (!document.all) && (!navigator.taintEnabled));
BO["safari"] = (document.childNodes) && (!document.all) && (!navigator.taintEnabled) && (!navigator.accentColorName);
BO["safari1.2"] = (parseInt(0).toFixed == null) && (BO["safari"] && (window.XMLHttpRequest != null));
BO["safari2.0"] = (parseInt(0).toFixed != null) && BO["safari"] && !BO["safari1.2"];
BO["safari1.1"] = BO["safari"] && !BO["safari1.2"] && !BO["safari2.0"];
return BO;
}
var BO = new detectBrowser();
The Explanation
There isn’t much to explain really. The function returns an object with boolean properties like BO.ie, BO.gecko etc. We suggest doing this check only once and storing the object where ever you might need it for later reference.
To check for IE we use a JScript only construct called Conditional Compilation, which sets BO.ie to true, but only for IE of course.
The other stuff does various object and method detections based on our knowledge of different implementations in different versions. This list is of course not complete, so if you have any additions that follow the same detection method please comment on this article. This is just what we have been needing so far.
on July 23rd, 2006 at 4:18 pm
Very nice, only thing one could comment about is the lag of IE3 support. But as many of our readers would agree there is close to no users using IE3 anymore.
on January 31st, 2007 at 1:43 pm
Just added IE7 support, since that was lacking.
That work by checking the JScript engine version, since that was updated for IE7.
I am not sure if this will work on machines with multiple Ie versions installed. If someone can check that it would be nice.
on August 16th, 2007 at 1:59 pm
Great articel!
I use another way to identify IE 7 by checking the window.XMLHttpRequest - just in case anybody is interested:
BO[”ie7″] = (BO[”ie”] && document.implementation != null && document.compatMode != null && window.XMLHttpRequest != null)
on September 7th, 2007 at 3:55 pm
IE3 support? what?! are you serious?
Most web apps today won’t support less than IE6, and even then, only grudgingly.
on January 8th, 2008 at 8:17 am
Using the code above, I was getting a false positive for ie6 on ie7 until I added a && window.XMLHttpRequest == null to the check for ie6.
on September 18th, 2008 at 1:55 pm
“Most web apps today won’t support less than IE6, and even then, only grudgingly.”
…
I only grudgingly make very small allowances for IE7 when I can help it, otherwise IE users are on their own ;) I know that is not really relevant to the article but I couldn’t resist.
As for this though: “I am not sure if this will work on machines with multiple Ie versions installed. If someone can check that it would be nice.”
If it is identifying itself as IE7 in javscript then you can just use all the normal IE7 javascript stuff anyway and it doesn’t matter what version the browser really is though, right? Or can you run into trouble when you try to do something to activex or what? Seriously I can think of no situation where you would ever want to feed IE7 Javascript to IE6’s parser, or vice versa.
And if you’re using it to set CSS stuff…. Bad bad bad!!! Style and behaviour are two totally separate things!!!!
This is why I avoid inline style declarations when I can help it, and why I try to reset the CSS a bit (and not be TOO rigid) for the elements my stylesheet cares about…
on July 14th, 2009 at 7:31 pm
Great exceptic point of view!
How would you add for detecting Firefox, Netscape?
Thanks to all