public
Last active — forked from padolsey/gist:527683

Very small IE detect (aka type coersion ftw)

  • Download Gist
very-small-ie-detect.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
// ----------------------------------------------------------
// A short snippet for detecting versions of IE in JavaScript
// without resorting to user-agent sniffing
// ----------------------------------------------------------
// If you're not in IE (or IE version is less than 6) then:
// ie === 0
// If you're in IE (>=6) then you can determine which version:
// ie === 7; // IE7
// Thus, to detect IE:
// if (ie) {}
// And to detect the version (after IE has been detected):
// ie === 6 // IE6
// ie > 7 // IE8, IE9 ...
// ie < 9 // Anything less than IE9
// ----------------------------------------------------------
 
// GOAL: the smallest possible minified size (without using conditional compilation)
 
// While using `with` makes automatic minification difficult (if not impossible)
// due to the fact that the minifier doesn't necessarily know which identifiers
// reference properties of the specified object versus variables in the scope
// chain, I'm using it here and minifying manually.
with ( document.createElement("b") )
// No curly braces needed for the `with` because only the following `for`
// loop (a single statement) needs to execute inside the `with`.
for (
// Initialize the for loop by declaring the `ie` var, setting its value to
// -1 (which will get incremented at least once).
var ie = -1;
// Increment `ie` and update the innerHTML of the element accordingly. If
// the browser is IE with a version greater than `ie`, "1" will be written
// into the element.
innerHTML = "<!--[if gt IE " + ++ie + "]>1<![endif]-->"
// Unfortunately, because testing innerHTML at the time of assignment is
// inadequate, a separate expression must be used. The comma operator allows
// both the preceding and the following expression to be evaluated, with
// only the last expressions's result affecting the for loop's condition.
,
// If non-IE (or a lower version IE), the innerHTML will be an empty string,
// which gets coerced to 0 (falsy) by the + operator. Otherwise, it will be
// "1" which gets coerced to 1 (truthy). Basically, as long as the innerHTML
// is "1", continue looping.
+innerHTML;
// Because `ie` is incremented in the condition, no increment expression is
// needed here!
);
 
// (It should go without saying that if the var was named `i` instead of `ie`,
// a few more bytes could be saved, but I'm saying it anyways, because that's
// how I roll)
 
// Minified (111 chars):
with(document.createElement("b"))for(var ie=-1;innerHTML="<!--[if gt IE "+ ++ie+"]>1<![endif]-->",+innerHTML;);
 
// Version without `with` in case that's how you roll (112 chars):
for(var ie=-1,b=document.createElement("b");b.innerHTML="<!--[if gt IE "+ ++ie+"]>1<![endif]-->",+b.innerHTML;);

My previous version was still quite small at 142 chars, because it used a closure, but the closure is really unnecessary in this case. View the live test page to see it in action. Also notice that ie === 0 in non-IE browsers.

Why do you use the unary plus operator in var ie = id > 5 ? +id : 0? It does nothing and adds a character to your minified version.

And why did you change the minimal IE version to detect to 6? IE 5 also supports conditional comments.

Marcel, I use + to cast id, which is a string, to a number. I changed the comment to more accurately reflect that this code detects a minimum version of IE6 (I don't really care about IE5 support).

Ah, I didn't know about the side-effect of typecasting of +. Indeed, according to the ECMAScript specification, + converts ToNumber(GetValue(expr)).

The only thing is, id is never changed into a string; only the innerHTML is.

In Chrome console, if you enter var b=document.createElement("b"); b.id=1; b.id, you get "1" (string).

Of course, I didn't think of the impact of the with statement.

Yeah, that's how I can get away with not needing a closure or temp var!

Great stuff, what's the license? Or is it so small, that it would fall under public domain?...

... also, how come var ie is inside the with, and id is missing var?...

I believe he is accessing the id as a property of the element (element.id), so it does not need a var declaration.

121 chars: with(document.createElement("b")){for(id=-1;innerHTML="<!--[if gt IE "+ ++id +"]>1<![endif]-->",innerHTML>0;);var ie=+id}

I haven't tested it very much, just Chrome, IE8, and IE8 in IE7 mode; though it shouldn't differ to much from Ben's.

It will also go through 5 or so extra loops in IE.

David, I managed to get it even smaller, down to 112 chars:

with(document.createElement("b"))for(var ie=-1;innerHTML="<!--[if gt IE "+ ++ie+"]>1<![endif]-->",innerHTML>0;);

But if you can't stand the with, it's still pretty small at 113 chars:

for(var ie=-1,b=document.createElement("b");b.innerHTML="<!--[if gt IE "+ ++ie+"]>1<![endif]-->",b.innerHTML>0;);

And changing the var name from ie to i would shave off another 2 chars!

\o/ for Code Golf! 108 chars now:

with(ie=-1,document.createElement("b"))while(innerHTML="<!--[if gt IE "+ ++ie+"]>1<![endif]-->",+innerHTML);

p.s., this last one doesn't care about local scope; it will take up residence in your window. It will clobber window.ie if it already existed.

I'm not really down with the global var solution, as it would make this unsuitable for inclusion in production code.. but your coercing +innerHTML was awesome, so I added it into my gist. Sweet!

Yah, I got a little carried away there.

Now we wait for @jdalton to find the one use-case where it will break. haha. :o)

Even better, you don't need explicit typecasting at all, just innerHTML will do the trick, too. ;-)

Marcel, have you actually even tried that cross-browser?

Yes, at least in FF4, IE8, IE8-acting-as-IE7, Chromium 10.

with(document.body)for(var ie=0;innerHTML="<!--[if gt IE "+ie+"]>1<![endif]-->",+innerHTML;ie++);

97 chars. Tested in IE 6-8, FF and Chrome, needs to be above body tag.

Also, firefox 3.6 needs the +innerHTML, can't use just "innerHTML"

Ah, I think I found out why. If you put that code in a script block before your body tag it will be executed before the body has content it seems... example

One very small correction in your code comments.

// If non-IE (or a lower version IE), the innerHTML will be an empty string,
// which gets coerced to 0 (falsy) by the + operator.

While it is the case for IE that innerHTML will be an empty string, for non-IE browsers you'll get the full HTML code comment:

<!--[if gt IE 0]>1<![endif]-->

...which is coerced to NaN by the unary + operator.

Of course the outcome is the same, as both 0 and NaN are "falsey".

(ie <= 7) is causing an error in IE8:

'Undefined' is null or not an object.

Such a sweet, sweet, slender piece of code. So.... what's the absolute smallest way to add detection for IE10 without conditional comments (not supported) or UA-sniffing? I think

document.body.style.msFlex

is the shortest :)

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.