For at least a decade, browser detection has gotten a bad rap. Test for the browser’s capabilities, not the browser itself,
we’re repeatedly told. But there are times when nothing else will do.
Not long after browsers became JavaScript-enabled – we’re back in the mid 90s now – browser sniffing was one of many cool tricks that became widely used. Query the navigator
object to get the browser name, version, and other attributes, then use that information to control other functionality, such as image rollovers.
Enter feature detection
This practice was eventually superseded by the more robust technique of feature detection. Instead of trying to identify the browser or browsers that needed special handling, test for support of the feature in question, and ignore the browser itself. Eventually, Modernizr appeared, a JavaScript library providing an easy, standardised way to test for a wide range of HTML5 and CSS3 features. When the page loads, Modernizr runs a series of tests and adds a class to the <html>
tag for every tested feature that’s supported, and a no-xxxxxx
class where the feature isn’t supported.
For example, let’s say your layout depends on a particular font supplied by the @font-face
rule. You’ve specified fallback fonts, but your desired layout will be messed up if these fonts get called (stay with me here). You simply write one CSS rule for the browsers that support @font-face
, and another for the rest, like so:
.font-face .example {
width: 80%;
padding: 2em;
}
.no-font-face .example {
width: 60%;
padding: 4em;
}
Making browser detection respectable again
In practice this works very well. But there are many use cases where you need to compensate for individual browser quirks rather than browser capabilities. Even though old versions of Internet Explorer are fading into the sunset, and even though each new version of IE seems to be less buggy than its predecessor, problems with floats, positioning, and other standardised CSS properties persist. These have nothing to do with capabilities per se – the browser is theoretically capable of dealing with them – rather the browser in question implements the particular capability in a flawed way. The most direct and reliable way to deal with the bug is to address the browser directly.
Better browser detection
Unlike the JavaScript navigator object, conditional comments are a reliable way to identify any version of IE between 5 and 9. The HTML5Boilerplate template uses conditional comments to identify if the current browser is Internet Explorer and, if so, what version it is. It uses a similar model to Modernizr in that it deploys a set of class names on the <html>
tag to allow the developer to target not only specific versions of IE, but ranges of versions of IE. For instance “IE 7 or earlier” would be identified by the class lt-ie7
.
Although it’s clever, I find HTML5Boilerplate’s technique of littering your page with four or more conditionally-commented <html>
tags cumbersome and unsightly. And once in a while you’ll stumble on a bug in a supposedly standards-compliant browser such as Safari, Chrome, or Opera. So I set about gathering up some existing, well-tested code into a single jQuery function that avoids the multiple <html>
tags, instead adding all the necessary classes to the single <html>
tag (see Downloads, below).
This function will detect Internet Explorer from version 5 through 10, and Firefox, Safari, Chrome, and Opera. It also detects the Webkit engine, used by both Safari and Chrome. It’s is only 1.3KB minified, so you can paste it into your main JavaScript file, inside the $(document).ready()
event handler. Assuming you’ve already called jQuery, all you need then do is call it on the $(document).ready()
event, as follows:
$('html').add_browser_classes();
As with Modernizr, you deploy it in your CSS as follows:
.not-safari .example {
padding: 2em;
}
.safari .example {
padding: 4em;
}
Downloads
Download the example code.
- jquery.add-browser-classes.js (full)
- jquery.add-browser-classes.min.js (minified)
Special thanks to James Padolsey for the IE detection routine, which I extended to detect IE10.