Browser Detection VS Feature Detection

This article is going to introduce some basic techniques about how to use both methods to detect browsers, and why is one method better than other other.

Browser Detection VS Feature Detection. Here you go:

1) Browser Detection

The traditional way is using JavaScript to parse userAgent strings to determine the browser. It is generally achieved by reading a browser property navigator.userAgent that returns a string with a lot of information about the browser that is currently being used to visit the page. Here is an example of what navigator.userAgent returns in different browsers:

// Firefox
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0)
 Gecko/17.0 Firefox/17.0"
// Chrome
"Mozilla/5.0 (Windows NT 6.1; WOW64)
 AppleWebKit/537.11 (KHTML, like Gecko)
 Chrome/23.0.1271.64 Safari/537.11"
// IE
"Mozilla/5.0 (compatible; MSIE 9.0;
 Windows NT 6.1; WOW64; Trident/5.0; SLCC2;
.NET CLR 2.0.50727; .NET CLR 3.5.30729;
.NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)"

The easiest way to do this is using jQuery.browser and jQuery.browser.version. Suppose you want to write the browser specific code, you can do something like this:

var ua = $.browser;
case msie:
  // IE code here...
case mozilla:
  // Firefox code here...
case webkit:
  // Chrome code here...
  //code to be executed if ua is different from above cases

Behind the scene, jQuery uses this technique to implement the Browser Detection. The following example is from jQuey-1.8.3. source code.

var matched, browser;

// Use of jQuery.browser is frowned upon.
// More details:
// jQuery.uaMatch maintained for back-compat
jQuery.uaMatch = function( ua ) {
    ua = ua.toLowerCase();

    var match = /(chrome)[ /]([w.]+)/.exec( ua ) ||
        /(webkit)[ /]([w.]+)/.exec( ua ) ||
        /(opera)(?:.*version|)[ /]([w.]+)/.exec( ua ) ||
        /(msie) ([w.]+)/.exec( ua ) ||
        ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([w.]+)|)/.exec( ua ) ||

    return {
        browser: match[ 1 ] || "",
        version: match[ 2 ] || "0"

matched = jQuery.uaMatch( navigator.userAgent );
browser = {};

if ( matched.browser ) {
    browser[ matched.browser ] = true;
    browser.version = matched.version;

// Chrome is Webkit, but Webkit is also Safari.
if ( ) {
    browser.webkit = true;
} else if ( browser.webkit ) {
    browser.safari = true;

jQuery.browser = browser;

If you read the above code cautiously, you would realize jQuery puts on some extra work for backward-compatibility purpose. This is an obvious drawback of using Browser Detection.

Suppose the browser changes the feature in the future, your code in this case will not be able to predict and handle it. In turn, when user updates their browser, your code may broke. That is the worst scenario in terms of user experience.

Plus, it's impossible to know exactly which features supported by which browser. I am not talking about something simple like addEventListener and attachEvent everyone knows, but something more trivial but vital to your web application.

2) Feature Detection

Feature detection is a much more reliable method to determine if you can use a feature in a specific browser. Let's take a look at a few examples first:

i) AJAX - Create an XMLHttpRequest Object

// All modern browsers support the XMLHttpRequest object
if ( window.XMLHttpRequest )
    xhr = new XMLHttpRequest();
// Old versions of Internet Explorer (IE5 and IE6) uses
// an ActiveX Object:
else if ( window.ActiveXObject )
    xhr = new ActiveXObject( "Microsoft.XMLHTTP" );

ii) Register an Event

var obj = {};
if ( obj.addEventListener ) {
    obj.addEventListener( ... );
} else if ( obj.attachEvent) {
    obj.attachEvent( ... );
} else {

iii) Modernizr is an awesome JavaScript Library which utilizes the Feature Detection. In it's source code, there is a wrapper function named testProps() to test if a property is legit to use in a certain browser. If the property is supported it will return an empty string; if unsupported it will return undefined.

function testProps( props, prefixed ) {
    for ( var i in props ) {
        var prop = props[i];
        if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
            return prefixed == 'pfx' ? prop : true;
    return false;

Now, let's use Modernizr to do some detection: (Modernizr.propertyname)

if (Modernizr.localstorage) {
    alert("This browser supports HTML5 localstorage!");
} else {
    alert("no localstorage:(");

Behind the scene, Modernizr does the dirty job for you:

tests['localstorage'] = function() {
    try {
        localStorage.setItem(mod, mod);
        return true;
    } catch(e) {
        return false;

Feature Detection doesn't reply on knowledge of which browser is being used, only on which features are available, which ensures supporting in new browsers.


jQuery recommends against using $.browser, use feature detection instead, see To see a full list of properties/methods supported by major browsers, check MDN Browser Feature Detection. Modernizr library makes feature detection so easy to use. Thanks to all those powerful libraries and great developers behind them.

Finally. as a web developer, my ultimate goal is "write once, run anywhere".

Yang Zhao

Read more posts by this author.