I’ve been reviewing bug submissions for the SWFObject project and was reminded of a big problem with SWFObject 2.2: the JavaScript technique it uses for detecting Internet Explorer does not work in Internet Explorer 9.

SWFObject 2.2 currently uses an IE detection technique proposed by Andrea Giammarchi in 2009:

var isIE = !+"v1";Code language: JavaScript (javascript)

It’s a hack that relied on Internet Explorer’s unique handling of vertical spaces (v). Now that it has stopped working, I decided to take a quick look at what others are doing.

One of my favorite approaches is Dean Edwards’ “sniff” technique, which takes advantage of Microsoft’s conditional compilation.

var isIE = /*@cc_on!@*/!1;Code language: PHP (php)

It’s 4 years old, but still works like a charm. The only problem is that some JavaScript compressors and optimizers (including YUI Compressor and Google Closure) have a hard time with the inline comment and strip it out. It makes the code difficult to maintain, because it requires editing post-compression.

One way to get around the compressor issue (as pointed out by a commenter on Dean Edwards’ post) is to wrap the conditional compilation statement in an eval() function:

var isIE = eval("/*@cc_on!@*/!1");Code language: JavaScript (javascript)

Since eval() is evil, I won’t use this approach.

One of the most long-standing methods of detecting Internet Explorer is to examine the userAgent string:

var isIE = /msie/gi.test(navigator.userAgent);Code language: JavaScript (javascript)

However, this isn’t foolproof, as most browsers allow you to change the userAgent string at will. For example, I changed Safari’s userAgent string to report itself as Internet Explorer 8, and /msie/gi.test(navigator.userAgent); returned true!

So far, the only test I’ve found that seems to fit the bill is the old navigator.appName test:

var isIE = navigator.appName === 'Microsoft Internet Explorer';Code language: JavaScript (javascript)

Is it perfect? Not a chance, but it has a lot of upside: it works in IE9, doesn’t get damaged when compressed, doesn’t rely on any hacky tricks (as fun as they might be), and isn’t affected by spoofed userAgent strings.

What are the Frameworks using?

jQuery uses userAgent sniffing, and includes a warning that it’s unreliable. MooTools uses a combination of properties from the navigator object, including navigator.userAgent and navigator.platform. It’s interesting to note that MooTools previously used feature detection to infer the browser brand, but changes introduced by Firefox 3.6 prompted the MooTools team to switch to a userAgent-based detection method instead. (Nicholas Zakas wrote an interesting blog post about MooTools’ prior detection technique.)
Dustin Diaz’s Bowser detection script uses userAgent exclusively.

Why sniff in the first place?

Before you get down on me for even talking about sniffing, relax, I agree with you. I much prefer feature detection to browser sniffing; this is especially important with our quickly changing browser landscape: HTML5, web storage, geolocation, etc. (Modernizr is a great tool for modern feature detection.)

But Internet Explorer always makes us do things we’re not quite comfortable doing. Sometimes it’s not very easy to detect IE’s support for a given issue. For example, IE is notorious for not allowing JavaScript developers to set the name attribute of form elements via setAttribute; it requires including the name in the createElement invocation. Craziness!

So we carry on. I use feature detection for just about everything, but once in a while I need a global “are you Internet Explorer?”, and browser sniffing fits the bill.

Similar Posts

5 Comments

  1. @jesse that’s an excellent approach, but unfortunately it’s also not pure JavaScript, so it will only work in specific circumstances. In the case of a JavaScript library like SWFObject, jQuery or MooTools, the library can’t depend on HTML-based conditional comments. I do like the concept, though; it’s the most foolproof way to not only detect IE but get the exact version being used.

  2. Gidday Pipwerks – I felt obliged to try and add in some browser sniffing after reading, I found the following worked a treat – it isn’t “elegant” but for IE it’s pretty solid:

    Am I IE?

    var p = document.createElement('p');
    p.innerHTML = '';
    p.style.display = 'none';
    document.body.appendChild(p);
    if(p.innerHTML === 'IE9'){
    	alert('This is... IE9!');
    }
    

    I did it with YUI3 initially, in the same # of lines of code, but reduced it to good ole JS.

    I’d also tried to avoid string testing, by dynamically creating script tags with a variable test inside – but then remembered that IE borks on that approach – maybe there’s a way to do it.

    but either way, creating an element with an inline conditional comment works as well as the comments themselves!

    cheers,
    d

  3. Doh – the important bit got stripped out when I submitted – but basically the innerHTML is set to be an IE conditional comment, all I put inside the comment was the string: “IE9”, which I then test for.

    – d

Comments are closed.