Correct way to use Modernizr to detect IE?

152,352

Solution 1

I agree we should test for capabilities, but it's hard to find a simple answer to "what capabilities are supported by 'modern browsers' but not 'old browsers'?"

So I fired up a bunch of browsers and inspected Modernizer directly. I added a few capabilities I definitely require, and then I added "inputtypes.color" because that seems to cover all the major browsers I care about: Chrome, Firefox, Opera, Edge...and NOT IE11. Now I can gently suggest the user would be better off with Chrome/Opera/Firefox/Edge.

This is what I use - you can edit the list of things to test for your particular case. Returns false if any of the capabilities are missing.

/**
 * Check browser capabilities.
 */
public CheckBrowser(): boolean
{
    let tests = ["csstransforms3d", "canvas", "flexbox", "webgl", "inputtypes.color"];

    // Lets see what each browser can do and compare...
    //console.log("Modernizr", Modernizr);

    for (let i = 0; i < tests.length; i++)
    {
        // if you don't test for nested properties then you can just use
        // "if (!Modernizr[tests[i]])" instead
        if (!ObjectUtils.GetProperty(Modernizr, tests[i]))
        {
            console.error("Browser Capability missing: " + tests[i]);
            return false;
        }
    }

    return true;
}

And here is that GetProperty method which is needed for "inputtypes.color".

/**
 * Get a property value from the target object specified by name.
 * 
 * The property name may be a nested property, e.g. "Contact.Address.Code".
 * 
 * Returns undefined if a property is undefined (an existing property could be null).
 * If the property exists and has the value undefined then good luck with that.
 */
public static GetProperty(target: any, propertyName: string): any
{
    if (!(target && propertyName))
    {
        return undefined;
    }

    var o = target;

    propertyName = propertyName.replace(/\[(\w+)\]/g, ".$1");
    propertyName = propertyName.replace(/^\./, "");

    var a = propertyName.split(".");

    while (a.length)
    {
        var n = a.shift();

        if (n in o)
        {
            o = o[n];

            if (o == null)
            {
                return undefined;
            }
        }
        else
        {
            return undefined;
        }
    }

    return o;
}

Solution 2

Modernizr doesn't detect browsers as such, it detects which feature and capability are present and this is the whole jist of what it's trying to do.

You could try hooking in a simple detection script like this and then using it to make your choice. I've included Version Detection as well just in case that's needed. If you only want to check of any version of IE you could just look for the navigator.userAgent having a value of "MSIE".

var BrowserDetect = {
        init: function () {
            this.browser = this.searchString(this.dataBrowser) || "Other";
            this.version = this.searchVersion(navigator.userAgent) || this.searchVersion(navigator.appVersion) || "Unknown";
        },
        searchString: function (data) {
            for (var i = 0; i < data.length; i++) {
                var dataString = data[i].string;
                this.versionSearchString = data[i].subString;

                if (dataString.indexOf(data[i].subString) !== -1) {
                    return data[i].identity;
                }
            }
        },
        searchVersion: function (dataString) {
            var index = dataString.indexOf(this.versionSearchString);
            if (index === -1) {
                return;
            }

            var rv = dataString.indexOf("rv:");
            if (this.versionSearchString === "Trident" && rv !== -1) {
                return parseFloat(dataString.substring(rv + 3));
            } else {
                return parseFloat(dataString.substring(index + this.versionSearchString.length + 1));
            }
        },

        dataBrowser: [
            {string: navigator.userAgent, subString: "Edge", identity: "MS Edge"},
            {string: navigator.userAgent, subString: "MSIE", identity: "Explorer"},
            {string: navigator.userAgent, subString: "Trident", identity: "Explorer"},
            {string: navigator.userAgent, subString: "Firefox", identity: "Firefox"},
            {string: navigator.userAgent, subString: "Opera", identity: "Opera"},  
            {string: navigator.userAgent, subString: "OPR", identity: "Opera"},  

            {string: navigator.userAgent, subString: "Chrome", identity: "Chrome"}, 
            {string: navigator.userAgent, subString: "Safari", identity: "Safari"}       
        ]
    };
    
    BrowserDetect.init();
    document.write("You are using <b>" + BrowserDetect.browser + "</b> with version <b>" + BrowserDetect.version + "</b>");

You can then simply check for:

BrowserDetect.browser == 'Explorer';
BrowserDetect.version <= 9;

Solution 3

You can use Modernizr to detect simply IE or not IE, by checking for SVG SMIL animation support.

If you've included SMIL feature detection in your Modernizr setup, you can use a simple CSS approach, and target the .no-smil class that Modernizr applies to the html element:

html.no-smil {
  /* IE/Edge specific styles go here - hide HTML5 content and show Flash content */
}

Alternatively, you could use Modernizr with a simple JavaScript approach, like so:

if ( Modernizr.smil ) {
  /* set HTML5 content */
} else {
  /* set IE/Edge/Flash content */
}

Bear in mind, IE/Edge might someday support SMIL, but there are currently no plans to do so.

For reference, here's a link to the SMIL compatibility chart at caniuse.com.

Solution 4

Detecting CSS 3D transforms

Modernizr can detect CSS 3D transforms, yeah. The truthiness of Modernizr.csstransforms3d will tell you if the browser supports them.

The above link lets you select which tests to include in a Modernizr build, and the option you're looking for is available there.


Detecting IE specifically

Alternatively, as user356990 answered, you can use conditional comments if you're searching for IE and IE alone. Rather than creating a global variable, you can use HTML5 Boilerplate's <html> conditional comments trick to assign a class:

<!--[if lt IE 7]>      <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->

If you already have jQuery initialised, you can just check with $('html').hasClass('lt-ie9'). If you need to check which IE version you're in so you can conditionally load either jQuery 1.x or 2.x, you can do something like this:

myChecks.ltIE9 = (function(){
    var htmlElemClasses = document.querySelector('html').className.split(' ');
    if (!htmlElemClasses){return false;}
    for (var i = 0; i < htmlElemClasses.length; i += 1 ){
      var klass = htmlElemClasses[i];
      if (klass === 'lt-ie9'){
        return true;
      }
    }
    return false;
}());

N.B. IE conditional comments are only supported up to IE9 inclusive. From IE10 onwards, Microsoft encourages using feature detection rather than browser detection.


Whichever method you choose, you'd then test with

if ( myChecks.ltIE9 || Modernizr.csstransforms3d ){
    // iframe or flash fallback
} 

Don't take that || literally, of course.

Solution 5

If you're looking for a JS version (using a combination of feature detection and UA sniffing) of what html5 boilerplate used to do:

var IE = (!! window.ActiveXObject && +(/msie\s(\d+)/i.exec(navigator.userAgent)[1])) || NaN;
if (IE < 9) {
    document.documentElement.className += ' lt-ie9' + ' ie' + IE;
}
Share:
152,352

Related videos on Youtube

Steve
Author by

Steve

Updated on September 25, 2020

Comments

  • Steve
    Steve almost 4 years

    I wanted to use the Modernizr JS library to detect for some browser properties to determine what content to show or not show.

    I have an app called Pano2VR which outputs both HTML5 and SWF. I need the HTML5 for iOS device users.

    However, IE does not render this "HTML5" output at all. It seems their output uses CSS3 3D transforms and WebGL, one or more apparently unsupported in IE9.

    So, for those users I need to display the Flash version. I was planning to use an IFRAME and either pass the SRC via a Modernizr script or document.write out the correct IFRAME code depending on browser.

    All of which leads to how do I use Modernizr to detect simply IE or not IE? Or detect for CSS 3d transforms?

    Or is there another way to do this?

  • Steve
    Steve over 11 years
    Thanks. I wound up finally tracking down that the issue was their file needed webgl support. So, I could use Modernizer to test for that and do a document.write of one code block of the other. But this is an excellent solution for browser detection. Thanks again.
  • Andrew Senner
    Andrew Senner about 11 years
    One thing to remember: The UA string is completely user-configurable.. So checking the UA string is NOT a consistent way of checking the browser. developer.mozilla.org/en-US/docs/DOM/window.navigator.userAg‌​ent In the "Notes" section: Browser identification based on detecting the user agent string is unreliable and is not recommended, as the user agent string is user configurable.
  • Jed Richards
    Jed Richards about 11 years
    Yes, but what percentage of users are browsing the web with a modified/spoofed/incorrect UA string? How much engineering time do you want to spend ensuring that tiny minority has an optimal experience on your site? Browser sniffing via UA string is a practical and sane approach.
  • Philip007
    Philip007 almost 11 years
    @Wintamute, can't agree more. Get sick of "feature detection is evil" kind of lecture. We are doing engineering, not pursuing art
  • rudimenter
    rudimenter almost 11 years
    Conditional comments are not more supported in internet explorer >=10.
  • Scott
    Scott almost 11 years
    You have a trailing comma after the last item in dataBrowser, that should be removed.
  • Scott
    Scott almost 11 years
    I should have also mentioned that I only found the comma because I'm copy/pasting your code word-for-word to use in my current project and jslint squawked at me for it. Thanks!
  • Rolf
    Rolf over 10 years
    It is the general assumption that if someone modifies their UA string, then they know what they're doing and they can deal with the consequences. In fact this is exactly what the UA string exists for - to declare browser version to the server. If the client wants to lie about that, then well, that's just life! Of course there is a small possibility of the string being change without the user's consent but in practice that's not a real concern - and hey are we supposed to feed the user and rub their back too?
  • ObjectType
    ObjectType over 10 years
    Added support for IE 11 (Trident). Gets the browser version (11) instead of the engine version (7). If you want the engine version take out: if (this.versionSearchString == "Trident") { this.versionSearchString = "rv"; } and then change the identity in dataBrowser so it doesn't give you Explorer 7 when it really is Trident 7.
  • wf4
    wf4 over 10 years
    Is there a way to add this function as a test as part of Modernizr, maybe returning something like Modernizr.addTest(result,function)? it would be really useful to have browser name added as a css class
  • Code Uniquely
    Code Uniquely over 10 years
    There are some examples of how you might do this at gist.github.com/danott/855078
  • Raptor
    Raptor over 10 years
    the code is working great, however it does not detect whether it's a desktop / mobile browser.
  • Code Uniquely
    Code Uniquely over 9 years
    Added IE11 Support which now uses the trident engine and a rv: number
  • Chris
    Chris over 9 years
    Personally I always try do feature based detection rather than browser detection
  • iono
    iono over 9 years
    @Chris Good for you, same here? I... don't think you actually read my answer.
  • Chris
    Chris over 9 years
    Yours was the first answer that actually suggests using feature detect so figured it might help another person if they read the comment
  • iono
    iono over 9 years
    @Chris oh, sorry. I thought you were condemning me for including the IE test.
  • kaxi1993
    kaxi1993 almost 9 years
    BrowserDetect.browser in opera writes chrome
  • Batman
    Batman over 8 years
    Best answer imo. So simple
  • user1245809
    user1245809 over 8 years
    There is one problem, Opera, Microsoft edge have also Chrome in their navigator, so I see Chrome as browser when i'm in Opera
  • Code Uniquely
    Code Uniquely over 8 years
    @user1245809, I added a extra line for 'OPR' to find the latest Opera versions. It works with MS Edge too. But as I said at the start of my answer, you really should use feature detection for the things you are using rather than relying on the browser and version numbers being correct. :) It sure does not tell you its a Mobile version for instance, or whether you can use FileAPI
  • Jason
    Jason over 8 years
    While this does work, it works for now. The whole point of feature detection and Modernizr is that you don't have to worry about what happens tomorrow. If Edge updates tomorrow with smil support, your code no longer works and you may not even know it.
  • jacefarm
    jacefarm over 5 years
    It remains that there are no plans for SMIL support in Edge.
  • Zia Qamar
    Zia Qamar over 4 years
    Not working on latest browsers. I tried on Ipad chrome. Still its saying Safari.
  • Jeremy Carlson
    Jeremy Carlson over 3 years
    This looked so simple, but apparently Edge now supports SMIL.