Wednesday, January 28, 2009

32 bytes, ehr ... 9, ehr ... 7!!! to know if your browser is IE

Update another clever trick from comments, which I will explain later:

if(!+"\v1") // true only in IE
if("\v"=="v")// true only in IE
try{IE=window=!1}catch(e){IE=!0}

it works, doesn't it?

The reason is simple, if we consider "\v" as a vertical space, browsers interpreter that check in this way:

!(+
1
)

where "not one" is always false, considering that 0 is always casted as false, and every other number is casted as true.

Internet Explorer will ignore the vertical space, trying to cast a "v" character into a number, thanks to the sign (plus or minus, it does not matter)

// How IE interpreters the code
!(+"v")

// where
isNaN(+"v") === true
// and where NaN is implicitly casted as false


About conditional comments


I read a lot of comments in both Ajaxian and other places ... well, guys, this is a trick as conditional comment is.
The day IE will interpret correctly the "\v" character, Opera or some other browser could implement conditional comments as well.
That's my simple point of view:
conditional comments could be stripped out from minifiers (not MyMin) and make code difficult do understand or maintain while this 7 bytes trick is portable, minifier/packer safe, and extremely easy to maintain (the day IE will be able to return a false, we'll have solved almost every cross browser problem thanks to JS2 but just in case, all we need to do, will be a simple replace with the isIE.Next trick)


Note this trick is library/hack proof. If you think that execScript check is enough, for example, consider this: top["execScript"]=null and/or libraries that implements execScript for other browsers.

52 comments:

Digitta said...

Useful and also tiny. What else can we ask!? ;-)

Gareth Heyes said...

Nice! Much better than...

var isIE=function() {
/*@cc_on
@if (@_jscript)
return true;
@else */
return false;/*
@end
@*/
}

Andrea Giammarchi said...

yep, it does not use conditional comments. That's the plus ;-)

Gareth Heyes said...

Hehe it was a challenge to beat but...

IE=top.execScript?true:false

28!!! :)

Gareth Heyes said...

Doh!

IE=top.execScript?1:0

21 :)

Andrea Giammarchi said...

sure Gareth, that's why I edited my entry: my trick is hack proof ;-)

Andrea Giammarchi said...

IE=!!top.execScript

and now read the note, your one is not a good check

Gareth Heyes said...

I like the !! trick :)

Yeah it can be overwritten but so can IE but I take your point.

V1 said...

Try / catch gives a small performance hit. So only use it if you MUST.. and there are no other options...

Andrea Giammarchi said...

Gareth, the point is that your trick is never reliable, while window or window property cannot be assigned in IE or it generates an Illegal assignment exception.

So, if wherever you want to be sure that the browser is IE, if you load external scripts, for example, you can always perform something like this:
if(function(IE){
try{IE=this.window=!1}catch(e){IE=!0};return IE
}())


@V1, you are generally right, but there are a lot of tests in try catch that you can perform once in a session and will not slow down the application at all.

Gareth Heyes said...

Did you miss my other comment?

//Works fine
IE='\v'=='v'

Andrea Giammarchi said...

Did you miss mine? :D
var IE = function(IE){try{IE=this.window=!1}catch(e){IE=!0}return IE}();
You can perform the check N times, if necessary, or use your own namespaced library object.

myCoolLib.IE = function(IE){try{IE=this.window=!1}catch(e){IE=!0}return IE}();

Gareth Heyes said...

Andrea, I don't get your point because you can easily create a function with:-

function isIE() {
return '\v'=='v';
}

and it event works on IE8

Andrea Giammarchi said...

Gareth, I thought it was an assignment ... are you sure it is true only with IE? If it is, sounds amazing (pelase try IE8 as well, thanks)

Gareth Heyes said...

Andrea yep positive. false in safari,ff,chrome,opera but true in IE7, IE8

Do I win now? ;)

Andrea Giammarchi said...

YES :D

DPP said...

And how about:
ie=/*@cc_on!@*/false;

or, if u need to know concrete version:

ie=/*@cc_on 'ie6'; @if(@_jscript_version==5.7) 'ie7'; @end @if(@_jscript_version==5.8) 'ie8'; @end@*/

Andrea Giammarchi said...

NO conditional comments please ;-)

Stuart Langridge said...

IE//@cc_on=1

is twelve bytes. Since we're specifically trying to detect IE (rather than detect a feature), conditional comments are the way to go. If IE9 suddenly supports \v then the test will break; conditional comments will not.

Gareth Heyes said...

@Stuart Langridge

Awesome bit of code but that will raise a error in other browsers because IE will be undefined.

kentaromiura said...

Dean Edwards long time ago, suggested me this code to get the IE version number:

var IEVersion = 0/*@cc_on+ScriptEngineMajorVersion()@*/;

I think is still working ;)

Andrea Giammarchi said...

the Stuart check is not the best one indeed.

IE=/*@cc_on!@*/!1;

this one is better ;-)

anyway, no conditional comments please 8-)

TaiPhanMem.org said...

Thanks for greate and cool tip :).

Gareth Heyes said...

I've found a way to detect every major browser using js quirks :D

http://www.thespanner.co.uk/2009/01/29/detecting-browsers-javascript-hacks/

smileham said...

Absolute genius!

Ife Okwumabua said...

has anyone submitted this IE check?

IE=(document.selection);

Andrew Clegg said...

Does \v have some special meaning in IE?

Or is the trick specifically that \v *doesn't* mean anything, so IE reads it as "a backslash followed by a v", but the other browsers just ignore the backslash and interpret it as a v?

Andrea Giammarchi said...

"\v" in IE means "v", so IE reads it as "v" without the backslash (other way then)
other browsers obviously do not consider those two character the same ;-)

Gareth Heyes said...

oxotnick from the slackers forums even managed to reduce it:-

!-'\v1'

Cybaer said...

Holy Jesus, what a crap! =;->

1. You don't know, whether future versions of IE behave the same way.

2. Don't blame yourself with conditional comments. Conditional comments are HTML stuff. The (even longer existing) version for JScript is called conditional compilation

3. Use conditional compilation for determing an IE. Yes, maybe CC will be used by another browser some day, but then, this other browser would use JavaScript, not JScript. So use CC and test for JScript as Gareth shows with @_jscript. Another browser vendor would implement another, new variable, i.e. @_javascript or @_ecmascript (although: the constant __ECMASCRIPT_VERSION__ is already on the way ...), at least for compatibility reasons. And if a browser vendor would really license MS' JScript (suck!) itself (so @_jscript would really trigger at Non-IEs), what makes you think, that the vertical-tab-hack wouldn't trigger on that script engine too? In that case, it could be much more complicated, to identify an IE ...

4. Last, but not least, it is not, not, NOT possible to conclude on the IE version from the version of the scripting engine! Both are totally separated - in theory and practice! I.e. IE 6 has come natively with JScript 5.6, so i.e. @_jscript_version will report "5.6" (see DPP's comment). Don't update the IE, but just install (or update) the Windows Scripting Host - a scripting engine for the Windows desktop, and you automatically update the IE's scripting engine too (my IE 6 reports JScript version 5.7, but is nonetheless an IE 6 with all its bugs and behaviours, and not an IE 7).
If you really want to know the IE-Version: use CSS hacks, which can be done dynamically too, and read out the resulting code by the styleSheets-object and its rules-collection (for easy, browser-independent setting and getting CSS rules see cssRule() ). If the IE doesn't recognize the CSS, then he will tell you (rule "UNKNOW"). But IE 8 has a new feature for determining the browser version respectivly the mode, the browser runs in (i.e. IE 8 emulating an IE 7) introducing document.documentMode (a "successor" of the already known document.compatMode). So in future there should be no need for using CSS hacks anymore ...

Andrea Giammarchi said...

Cybaer do I miss something? You posted as nobody else had a clue about conditional comments. If you read comments I already wrote this:
IE=/*@cc_on!@*/!1;
which is the shortest conditional comment to know if the browser is IE.
The point is, still, this trick is about a "feature" presents only in IE so NO CONDITIONAL COMMENTS. Got the point? :)

Cybaer said...

Hi Andrea,

yes, sorry, you miss something. IMHO you miss two things:

First, your example is not a conditional comment, which is like this: <!--[if IE]>I'm IE<![endif]--> (a special sort of HTML comment, which you know for sure ;-)).

But what you mean is conditional compilation (a special sort of JScript comment).

No need to mix up the names though. ;-) They are defined as is - and docs can be found in the net by that names.

And second, with this shortest type of conditional compilation you wrote, you can get up in the mess, if (and only if) another browser vendor also implements conditional compilation. To avoid that (somewhere less probable but possible) situation, it would be safer to check for @_jscript. (Indeed, I would like both CC's to be implemented on other browsers! ;-))

So you are right - at the moment! Only IE knows conditional compilation (and @_jscript is always true) for now. The short line fullfill its task.

But if a browser like Mozilla would start to implement conditional compilation too, this short line will set your variable IE to true, although the browser is a Mozilla and not an IE. Because of that it is just safer, to check for @_jscript, because a Mozilla conditional compilation would, no: has to set this variable to false.

Both features, conditional compilation and conditional comments are proprietary IE stuff for now. But both features are able to be implemented in other browsers (think also of not yet working, but theoretically possible <!--[if Moz]>I'm a Mozilla<![endif]-->).

Got the point? ;)

Andrea Giammarchi said...

still, conditional compilation is a feature as !+"\v1" is. If we need to think about future problems with @cc_on, why on earth we cannot simply do the same with !+"\v1"?

What I mean is that:
1 - the trick is without conditional comments (compilation) on purpose
2 - whatever we are talking about is a "feature" of a single browser.

Are you sure M$ will support @cc_on or @_jscript in the future?

'Cause rumors say IE9 could adopt WebKit, in that case this "trick" will work perfectly, your one will mess up your code (but again, we are talking about 1 single variable definition, I'll never get this "religious war" about a 7 bytes to change when and if necessary in a far future ...)

Got the point? :P

Cybaer said...

> Are you sure M$ will support @cc_on or @_jscript in the future?

No, I'm not sure.

Sure, M$ is particularly concerned to be backwards compatible to older IEs. They say that, and you can see that in maaaany examples. But nobody can be sure. At least, because CC is (in my opinion as "ordinary JS developer") often used just for IE workarounds.

And if, in a distant future, an IE x would be complete compatible to other browsers, maybe there is no need for CCs anymore (although I think, MS didn't invented CCs only for that purpose =;-), so a sort of "IE JScrip developer" could see CCs with other eyes than I do).

On the other hand: what makes you think, that no other browser in the future would never handle a vertical tab the way IE does now? What makes you even think, that there isn't such a browser today on the market? There are maaany HTML clients out there beside the big ones we know for the standard computer. I don't know all of them. I suppose you also don't know them all, don't you?! ;-)


Another small example: JS can not handle text variables with linebreaks in it like PHP does:

$phptext="line1
line2
line3";

But newer JS-browers can handle a sort of that:

jstext="line1\
line2\
line3";

Older JS-browsers can't handle that, and need the oldschool type:

jstext="line1\nline2\nline3";


What I want to say is, I think it's just better to rely on a documented feature from a company which is well known to preserve backwards compatibility at many costs (if not at all costs - because they made their software incompatible to the rest of the world, for business purposes and don't want their customers tell "what we did was wrong, sorry for your inconvenience, but don't stop to pay us in the future either" ;->).

I don't want to rely on something I could barely overview ...

So I think the opinions are exchanged, let the folks decide on their own. ;-)

PS: Change of subject to the mentioned "IE version recognition" because I really don't want that to be forgotten are overviewed: Don't try to get the IE version out of the JScript version. This is not a point of "future" or "opinion", this is just provable fact in todays computing ... ;-)

Andrea Giammarchi said...

Cybaer, as long as this trick works perfectly I do not get a reason to change the subject.
We all do not know about the future and your assumptions could not be correct.
Think about IE5 for Mac, they simply stopped to support it.
If IE9 will adopt WebKit they could choose to leave old IE to the history.
So we still are in the future and opinion subject.
Finally, as I said before: I'll never get this "religious war" about a 7 bytes to change when and if necessary in a far future.

the isIE or IE variable is a single point in an entire application, if somebody is scared about maintain their applications, something we all have to do in any case, well, they can decide which way is better.

Cybaer said...

Hi Andrea,

sorry, misunderstanding!

With "change of subject" I didn't thought of this blog entry's title, but about the subject of our "comment dispute". Because DPP and kentaromiura wrote in their comments, that it is possible to get the IE version by checking the version of the scripting engine. "Our" dispute is one based on "opinions". But the tips for version checking are just wrong, which should not be overlooked ...

Best regards!

xPheRe said...

Nice one!
I used your !+"\v1" detection in my simple flash embedding script and it works like a charm.
Thank you!

Aleko said...

I think my decision better

ie=!-[1,]

Andrea Giammarchi said...

so @Aleko, please enlighten the world about how your 9 bytes are better than Gareth 8 ...

Aleko said...

Why 9 ??? 6!!!!

!-[1,]

or even

-[1,]

(but it returns false in ie and true in all others)

Andrea Giammarchi said...

my apologies, I counted in a wrong way. Just one question: are you sure this is not going to throw errors in older IEs? If not, we've got a new winner ;-)

Andrea Giammarchi said...

I think next test to do is about minifier/compilers ... as example, Closure Compiler will throw an error. It won't with Gareth one since that's just a string.

Aleko said...

I tested it in IETester and errors have not received - conversion is simple. About closure compiler - i'll think...

sorry for my rude english, i'm russian =)

Compressors has swallowed it without errors (http://compressorrater.thruhere.net/)

DJ Maze said...

I always use:

var ie=0/*@cc_on +(document.documentMode||@_jscript_version*10-50)@*/

Why?
Each IE version has other bugs so i know the version of IE AND if it is IE.

Aria Kerry said...
This comment has been removed by the author.
buy Viagra said...

I would like to say that you really made my day, it's wonderful when you just look around the web
and find something like this, reminds me of that ''How to make a dinner for a romantic...'' by Elsa Thomas,
you're a wonderful writer let me tell you!!! ñ_ñ

James Maverick (maverickhunterjames@gmail.com)
3453 Rardin Drive
San Mateo, CA 94403
Project Manager
650-627-8033

kamagra online said...

Amazing trick..very helpful..keep posting like this.

hongnk said...

if(!+"\v1") doesn't work after compress code with AjaxMin. Use top.execScript safer.

saç ekimi said...

> Are you sure M$ will support @cc_on or @_jscript in the future?
tr

Buy Kamagra said...

Thanks,

Helped me a lot. Hate IE

buy and sell said...

Useful post! I'm one of those who really deslike IE.

free ads website said...

IE it not as bad as you said here...