Adjit
Adjit

Reputation: 10305

Why is jQuery $.browser.safari true in Chrome?

In my Chrome Version 36.0.1985.125 m console, using jQuery 1.7.1.

I tried :-

$.browser.safari
true

Why does this return true?

$.browser.webkit

also returns true for me under the same conditions.

Upvotes: 0

Views: 323

Answers (1)

BoltClock
BoltClock

Reputation: 724452

This is why browser sniffing is so highly frowned upon: it's a complete mess, and you would do well to not even consider doing it, ever.

The Chrome user-agent string contains the substring "WebKit", and this includes versions of Chrome that use the Blink engine instead of the original WebKit build, since Blink itself originated as a fork of WebKit. For example, here's mine:

Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36

You can see that nowhere in this user-agent string is Blink even referred to by name; it's still referred to as AppleWebKit!

jQuery's browser detection via the $.browser property consisted of nothing more than a series of simple regex matches on navigator.userAgent for the relevant keywords. This is mentioned in the documentation, but more importantly, the source code reflects this:

  1. Line 60:

    // Useragent RegExp
    rwebkit = /(webkit)[ \/]([\w.]+)/,
    ...
    
  2. Line 75:

    // Keep a UserAgent string for use with jQuery.browser
    userAgent = navigator.userAgent,
    
  3. Line 899:

    browserMatch = jQuery.uaMatch( userAgent );
    if ( browserMatch.browser ) {
        jQuery.browser[ browserMatch.browser ] = true;
        jQuery.browser.version = browserMatch.version;
    }
    

Now, these snippets address why $.browser.webkit is true for Chrome. But what about $.browser.safari? Clearly, Safari and Chrome are two totally different browser products, even if their rendering engines share a heritage, so why would safari also be true for Chrome?

The answer can be found in the block immediately following the uaMatch() call above:

// Deprecated, use jQuery.browser.webkit instead
if ( jQuery.browser.webkit ) {
    jQuery.browser.safari = true;
}

In other words, the same value was being reflected for both $.browser.webkit and $.browser.safari. This seems strange, but then if you look at the Chrome user-agent string again, you'll notice that Safari is referred to by name as well! So even if they didn't try to synonymize Safari and WebKit, the user-agent string would have matched them both for either browser anyway.

Now you may ask, why was this never fixed? Why not just introduce a chrome property to $.browser to handle things differently for Chrome? That's because $.browser itself was deprecated in jQuery 1.3, released in early 2009, at which time Chrome was still the new kid on the block that everybody on the Web was talking about. (And, just for the record, that's over five years ago now.) Given that browser sniffing was already uncool at the time, there was little to no incentive to fix this, so they deprecated it and left it as it was.

Upvotes: 5

Related Questions