Internet Explorer Browser Detector




Note...

The Javascript code we are about to discuss relating to Internet Explorer detection is already included in the PluginDetect library. The PluginDetect properties that reveal the results of this browser detection are listed here.



Internet Explorer Detection

When trying to detect Internet Explorer via Javascript, it would be nice to use a method that does not depend on the navigator.userAgent. The user agent can be modified in many browsers these days, and so any detection code that looks at the user agent will not be 100% reliable. For this reason, I prefer to detect Internet Explorer using this:

var isIE = /*@cc_on!@*/!1;  // [Boolean]


This code is originally from Dean Edwards. The nice thing about this is that it utilizes a conditional compilation, which only runs on Internet Explorer.

There is one small drawback here. Some Javascript minifiers may not recognize conditional compilations, and would thus remove them from your script. To get around this issue, we place the code into a string as follows:

var isIE = new Function("return/*@cc_on!@*/!1")( );  // [Boolean]


[ Note: It is possible to use eval("...") instead of new Function("...")( ). However, my own testing has shown that when you use eval, the Yui compressor may not minify all of your local variable names. Hence we use new Function instead. ]



Internet Explorer Detection (Update)

It appears that Internet Explorer 11+ no longer supports conditional compilations. Therefore, we need to come up with a new method of detection. We still prefer to have a method that does not depend on the navigator.userAgent.

Our new method of IE detection has 2 parts to it:

 

1) We look at the document.documentMode. If this property is READ ONLY and is a number >=0, then we have Internet Explorer 8+.

2) If that does not work, then see if the browser supports conditional compilation.
If so, then we have Internet Explorer < 11.


And so we have the following method of detection:


var tmp = document.documentMode, e, isIE;

// Try to force this property to be a string.
try{document.documentMode = "";}
catch(e){ };

// If document.documentMode is a number, then it is a read-only property, and so
// we have IE 8+.
// Otherwise, if conditional compilation works, then we have IE < 11.
// Otherwise, we have a non-IE browser.

isIE = typeof document.documentMode == "number" || new Function("return/*@cc_on!@*/!1")( );

// Switch back the value to be unobtrusive for non-IE browsers.
try{document.documentMode = tmp;}
catch(e){ };



It may not be pretty or elegant, but it appears to work. Our method is not affected by a user modifying their userAgent. Nor is it affected by any extraneous Javascript code that modifies the document.documentMode property (or any other property) on a non-IE browser.



Detecting the True Internet Explorer Version


The TRUE version of IE is given as a string in the form of "AA.BB.CCCC.DDDDD". You can see the version when you look in the IE Help Menu. The only way I know of to detect the true version via Javascript is to use clientCaps. The True version, when derived from clientCaps, is completely independent of Internet Explorer's navigator.userAgent, document mode, and browser mode. It will/should give you the real, actual browser version regardless of the browser settings. [Note: In the Internet Explorer Developer Tools Menu, it is possible for a user to modify the user agent, the document mode, and the browser mode. These user modifications can affect a number of IE version detectors, but not this one.]

We can use clientCaps by creating a <tag>, assigning the client caps behavior to that <tag>, and then querying the getComponentVersion() method:

 

var e, obj = document.createElement("div"), x,
   verIEtrue = null,  // True IE version [string/null]
   CLASSID = [
       "{45EA75A0-A269-11D1-B5BF-0000F8051515}",  // Internet Explorer Help
       "{3AF36230-A269-11D1-B5BF-0000F8051515}",   // Offline Browsing Pack
       "{89820200-ECBD-11CF-8B85-00AA005B4383}"
   ];

try{obj.style.behavior = "url(#default#clientcaps)"}
catch(e){ };

for (x=0;x<CLASSID.length;x++)
{
   try{verIEtrue = obj.getComponentVersion(CLASSID[x], "componentid").replace(/,/g,".")}
   catch(e){ };
   if (verIEtrue) break;
};


A few observations on the above code:

1) clientCaps works for IE 5 thru IE 10. It should work for both 32 bit and 64 bit Windows. However, clientCaps does NOT work for IE 11 and higher. Microsoft decided to remove this functionality for IE 11+.

[Note: If the document mode for IE 11 is 10 or lower, however, then clientCaps will work. This is due to backwards compatibility. So, for example, we could have a web page that has <meta http-equiv="x-ua-compatible" content="IE=10"> in the <head> of a web page. This would force Internet Explorer 11's document mode to be 10, but it would allow clientCaps to work. Thus you could get the true version of IE 11 in this way.]

2) This code has been tested and verified on IE Desktop 5.5, 6, 7, 8, 9, and 10. You will note that it is not even necessary to insert the <div> into the DOM in order for this code to work. If you want this method to also work for IE 5, then you would have to insert the <div> into the DOM, then set the obj.style.behavior, and then use getComponentVersion().

3) It appears that you can use pretty much any tag with client caps, even a custom tag. Thus you could even use the following: obj = document.createElement("clientCaps"). Or you could simply attach the style.behavior property to a tag that is already in the DOM, such as the <html> tag, the <head> tag, or the <body> tag. IE does not seem to mind either way.

4) The getComponentVersion( ) method gives a string with commas, such as "AA,BB,CCCC,DDDD". We replaced all commas "," with "." because then you can easily convert to a floating point number via parseFloat( ).


5) You could add some code that handles the case when/if this clientCaps technique fails.

6) Some people have attempted to get the IE version by looking at the Jscript version. The problem with that is that you would have to update your code every time a new IE browser version came out. It is even possible for more than one Jscript version to be associated with the same IE version.

7) It is also possible to detect the IE version using conditional comments. This method is independent of the user Agent. However, the behavior of conditional comments for IE 8 & 9 are affected by the browser mode (in the Developer Tools menu). Microsoft has discontinued conditional comments for IE 10 and higher, and therefore this detection method cannot be used for IE 10+.

8) It is also possible to detect the IE version using the navigator.userAgent. But the user agent can be modified by the user, and so does not reveal the true browser version.



Detecting the Document Mode for Internet Explorer

The document mode for IE is given by the following:

 

var docModeIE = document.documentMode;   // for IE 8+


The document mode property tells us what level of HTML/Cascading Stylesheet (CSS)/Image support that the browser has.

For example, let us say that you are using IE 9 and you decided to change the documentMode (via the Developer Tools menu) to "8". This means that your browser would display web pages as though it were IE 8 in Standards Mode, even though you are really using IE 9. The CSS property "opacity", which is only available in IE 9 or higher in Standards Mode, would not work because it is displaying the web document as though it were IE 8.

If, on the other hand, you were to change the documentMode (via the Developer Tools menu) to "Quirks Mode", then the document.documentMode would be "5". The browser would only support HTML/CSS/Images at the level of IE 5 (or possibly IE 6).

The document.documentMode property is only available for IE 8+ or higher. (I am not certain what versions of IE Mobile have the documentMode property). Because of this, we might find it useful to determine what the effective document mode would be for lower versions of IE. We can do this by looking at document.compatMode (which is "BackCompat" or "CSS1Compat"). Using this information, we can get a document mode for IE 6+ as follows:

 

// convert verIEtrue string to floating point number
var verFullFloat = parseFloat(verIEtrue || "0", 10);

// Get the IE browser document mode.
var docModeIE = document.documentMode ||    // for IE 8+

// document.compatMode is available for IE 6+.
// If Quirks mode, then return 5

((/back/i).test(document.compatMode || "") ? 5 : verFullFloat) ||

// Else return IE browser version from the user agent
((/MSIE\s*(\d+\.?\d*)/i).test(navigator.userAgent || "") ? parseFloat(RegExp.$1, 10) : null);



The possible values for docModeIE are now given as:

 

5              IE 5 Mode (Quirks Mode)
6              IE 6 Standards Mode
7              IE 7 Standards Mode
8              IE 8 Standards Mode
9              IE 9 Standards Mode
10            IE 10 Standards Mode
11            IE 11 Standards Mode
etc...


docModeIE should give you the effective document mode for IE 6 and higher.



CSS, documentMode, and Conditional Classes


Sometimes, IE does not display a web page correctly, and so it becomes necessary to add some style rules specifically for IE to fix things. There are a few ways that web designers can do this:

1) Use browser specific CSS hacks. This is not valid according to the W3C and so should be avoided.


2) Use conditional stylesheets, where we use conditional comments to specify a stylesheet, such as:

<link rel="stylesheet" type="text/css" media="screen" href="style.css" />

<!--[if IE 6]>
    <link rel="stylesheet" type="text/css" media="screen" href="ie6.css" />
< ![endif]-->

<!--[if IE 7]>
    <link rel="stylesheet" type="text/css" media="screen" href="ie7.css" />
< ![endif]-->


The problem here is that you have a separate css file for each IE version, which is a bit messy and requires an additional HTTP request.


3) And then there is the idea from Paul Irish that one can conditionally add a class to the <html> tag, specific for each IE version:

 

<!--[if IE 6]> <html class="ie6"> <![endif]-->
<!--[if IE 7]> <html class="ie7"> <![endif]-->
<!--[if IE 8]> <html class="ie8"> <![endif]-->
<!--[if gt IE 8]><!--> <html> <!--<![endif]-->


and so all your browser specific css goes into one file:

 

div.foo { color: inherit;}
.ie7 div.foo { color: #ff8000; }


There are, however, a few minor drawbacks here. First of all, IE 10 and higher no longer supports conditional comments. So you can only use conditional comments for older versions of IE. [On the other hand, IE 10+ should be much more standards compliant, so you may not need to worry about CSS bugs in IE 10+.]

And second, conditional comments do not necessarily always give you the correct browser version number. That is to say, conditional comments do not necessarily tell you the correct level of CSS support in your browser. For example, let us pretend that you are using IE 9. It is possible for the user to modify the document mode (via the Developer Tools menu) to IE 7 Standards mode, while keeping the browser mode as IE 9. The browser would render a document as though it were IE 7, but the conditional comments would still behave as though the browser were IE 9. So the conditional comments would cause the wrong style rules to be used. [Though I have to admit, this is an unlikely scenario. Just remember that you would want to set both the document mode and the browser mode to the same level.]

And third, the markup is a little bit messier, all because of one single browser. Can you guess which browser that is?

Regardless, I believe that using conditional classes on the <html> tag is very useful.


4) My own personal preference is to use Javascript to set the classes, as opposed to conditional comments. We can use Javascript to get the IE document mode (which correctly reflects the level of browser CSS support), and based on that we set the appropriate class on the <html> tag. The document.documentMode number is officially available for IE 8 and higher, and one can easily extend this to lower versions of IE. Then we can set the <html> class using code similar to this:

// Set <html> classes
var html = document.getElementsByTagName("html")[0];
if (isIE){
   html.className = html.className || "";
   if (docModeIE == 5) html.className += " ie5";
   if (docModeIE == 6) html.className += " ie6";
   if (docModeIE == 7) html.className += " ie7";
   if (docModeIE == 8) html.className += " ie8";
};


and then it is a simple matter to create your browser specific css:

div.foo { color: inherit;}
.ie5 div.foo, .ie6 div.foo { color: #ff8000; }

 

Of course, the one major drawback of this technique is that it requires Javascript to be enabled. So this method is not perfect either.

Though I suppose if you were really picky, you could use both Javascript and conditional comments to set the classes. If Javascript detects that the conditional comments gave the wrong className**, then Javascript could correct that.

[** For IE 10+, conditional comments do not work. So Javascript would be the only way to set the className. For IE 8 & 9, if a user sets the document mode to be different from the browser mode, then the conditional comments may give the wrong className.]







Top of Page