The Web Developer Toolbox: Modernizr

This is the third in a series of articles dedicated to useful libraries that all web developers should have in their toolbox. The intent is to show you what those libraries can do and help you to use them at their best. This third article is dedicated to the Modernizr library.

Introduction

Modernizer is a library originally written by Faruk Ateş.

It is one of the key libraries for building cross-browser websites or applications in a modern fashion. The heart of the library is the web design pattern known as Progressive enhancement & Graceful degradation. This design pattern does not require Modernizr, but Modernizr can make things a lot easier. It detects the availability of native implementations for next-generation web technologies such as HTML5 or CSS3 and allow you to adapt your application accordingly, which is way better than trying some ugly voodoo user-agent sniffing.

Basic usage

Using this library is amazingly simple: Download it, link it to your pages—you’re done!

Modernizr will automatically add some CSS classes to the root html element. For example if you want to test Web Sockets support, it will add a websockets class to the html element if the browser supports that feature, otherwise it will add the no-websockets class. It will do the same with JavaScript by adding a global variable Modernizr.websocket with a boolean value.

Let’s see a simple example: Doing some stuff with RGBa colors.

First: Download a customized version of Modernizr

Modernizr, download page.

Second: Link it to your document

<!DOCTYPE html>
<!--
The "no-js" class is here as a fallback.
If Modernizr is not running, you'll know
something is wrong and you will be able to act
accordingly. In contrast, if everything goes well,
Modernizr will remove that special class.
-->
<html class="no-js">
<head>
    <meta charset="utf-8">
    <title>I want to do stuff with RGBa</title>
    <script src="modernizr.js"></script>
</head>
<body>
...
</body>
</html>

Third: Use it

With CSS

.rgba div {
    /* Do things with CSS for browsers that support RGBa colors */
}
 
.no-rgba div {
    /* Do things with CSS for browsers that DO NOT support RGBa colors */
}

With JavaScript

if(Modernizr.rgba) {
    // Do things with JS for browsers that support RGBa colors
} else {
    // Do things with JS for browsers that DO NOT support RGBa colors
}

Let’s see this silly example in action:

%CODEtoolbox-3-1%

Advanced usage

The basic usage is already awesome when you have to deal with a heterogeneous environment (such as mobile browsers for example), but there’s more.

Conditional loading

Modernizr offers a convenient way to do conditional loading. Actually, the YepNope library is a standalone spin-off of the Modernizr project. So, if you wish, you can bundled YepNope directly inside Modernizr. It’s perfect if you want to load based polyfills depending on specific browser capacity.

Modernizr.load({
    test: Modernizr.indexeddb,
    nope: "indexeddb-polyfill.js"
});

This is a very powerful tool: do not hesitate to read the documentation. Note that the Modernizr team maintain a list of very accurate polyfills. Feel free to use whatever you need (with caution, of course).

Custom tests

Modernizr come with a set of 44 tests for mainstream technologies. If you need to test some other technologies, Modernizr provide an API to build and plug your own tests.

// Let's test the native JSON support ourselves
Modernizr.addTest('json', function(){
    return window.JSON
        && window.JSON.parse
        && typeof window.JSON.parse === 'function'
        && window.JSON.stringify
        && typeof window.JSON.stringify === 'function';
});

Assuming the above test passes, there will be now a json class on the HTML element and Modernizr.json will be true. Otherwise, there will be a no-json class on the HTML element and Modernizr.json will be false.

Dealing with CSS prefix

CSS prefixes is a very sensitive subject. Modernizr provides cross-browser code to take care of this issue. Modernizr offers a very useful tool to deal with this: Modernizr.prefixed(). This method works with CSS properties (in the CSS OM camelCase style) as well as with DOM properties.

For example, Modernizr.prefixed("transition") will return “MozTransition” with Firefox but “WebkitTransition” with Safari and Chrome.

Testing media-queries

There is currently no simple way to test a media query from JS in any browser. To help with that, Modernizr has a special tool: Modernizr.mq(). This method will test the media query of your choice and will return true or false accordingly.

if(Modernizr.mq("screen and (max-width: 400px)")) {
    // Do some stuff for small screens
}

Limits and precautions

This library is a fantastic tool but it’s not magic. You should use it with caution and do not forget about other techniques to deal with unpredictable behaviors. For example, do not forget to rely on the CSS cascade when it’s sufficient.

The following example is a huge misuse of Modernizr:

div {
    color : white;
}
 
.rgba div {
    background : rgba(0,0,0,.8);
}
 
.no-rgba div {
    background : #333;
}

If for some reason Modernizr is not executed, your text will not be readable (white text over a white background). In this specific case, you are better doing the following (which, by the way, is also easier to read and maintain):

div {
    color : white;
    background : #333;
    background : rgba(0,0,0,.8);
}

So, don’t be blind when you use this library, take the time to think about what will happen if Modernizr is not available. In many case you have existing fallbacks, don’t forget to use them.

Conclusion

Modernizr is the most useful tool when you have to build large cross-browser stuff, from the oldest Internet Explorer 6 to the latest Firefox Nightly. Once you master it, you will be able to add some magic to your sites and applications. However, as with all the powerful tools, it takes some time to become comfortable with and to use it wisely at its full potential. But, Modernizr is definitely worth the effort.

About Jeremie Patonnier

Jeremie is a Mozilla contributor to MDN and personally dedicated to the promotion of the Open Web. He has been working since 2000 with Front End development for the web in France. He also blogs in French at http://jeremie.patonnier.net or http://typographisme.net, tweets as @JeremiePat and loves to share his knowledge with everybody.

More articles by Jeremie Patonnier…


16 comments

  1. Skoua

    This post is way clearer than the Modernizr doc!
    Thanks!

    July 17th, 2012 at 08:22

    1. Jeremie Patonnier

      You’re welcome :) However, the Modernizr doc is much more complete ;)

      July 17th, 2012 at 14:34

  2. Vlad

    Modernizr is great and your article is indeed very clear. Nowadays I encourage everybody to use it.

    July 18th, 2012 at 06:10

  3. Federico Brigante

    I think your usage is incorrect… maybe, it depends on how we approach the problem.

    Ideally, a website should work without the need of javascript, why should we rely on a script (which may fail to load or execute) to apply basic styles?

    Overlooking the quick fix provided by directly overriding a property like you suggested under “Limits and precautions,” one could use progressive enhancement this way:

    div { /* no rgba, default, no js required */
        background : #333;
    }
    
    .rgba div { /* with rgba, requires js */
        background : rgba(0,0,0,.8);
    }
    

    BUT! How about doing the opposite?

    div { /* let's presume rgba is supported */
        background : rgba(0,0,0,.8);
    }
    
    .no-rgba div { /* if it isn't, fix it with javascript (Modernizr) */
        background : #333;
    }
    

    This is basically the same way polyfills work, they rely on javascript to “fix” old browsers. We already rely on html5shim in oldIE to enable styling of HTML5 elements, so I think we should use the same approach for CSS features.

    July 18th, 2012 at 16:55

    1. Jeremie Patonnier

      a website should work without the need of javascript

      I strongly agree :)

      why should we rely on a script (which may fail to load or execute) to apply basic styles?

      We shouldn’t, that’s why I show a simple usage of the CSS cascade as a best practice under “Limits and precautions”

      How about doing the opposite?

      div { /* let’s presume rgba is supported */
      background : rgba(0,0,0,.8);
      }

      .no-rgba div { /* if it isn’t, fix it with javascript (Modernizr) */
      background : #333;
      }

      The problem here is that if for some reason a browser does not support RGBa AND the script is not working (and there is many reason to have a script not working), your site will be broken (no background at all). When you do it the other way, you will never face such an issue. However, when we are talking about CSS, it’s always safer to relay on the cascade as much as possible to deal with a lack of CSS support in browsers.

      This is basically the same way polyfills work, they rely on javascript to “fix” old browsers.

      Yes but we should always take care about polyfills. Using a polyfill is never a safe move and it’s important to always check that what we emulate with a polyfill will never break hard the user experience if the polyfill does not work. The web is a really wild place therefor it’s really important to deal with the unknown and it requires high discipline when coding. A polyfill is not magic, it’s just a patch on a bleeding scare.

      July 19th, 2012 at 02:04

      1. Federico Brigante

        Let’s be honest here, if you use advanced features your website will break without javascript in some browsers (i.e. IE8- when using html5shim).

        My point was, since we are already relying on JS in oldIE, let’s rely on JS only in those browsers, not in newer ones. Therefore, use the javascript-enabled “.no-feature” to fill in features, not the “.feature” in modern browsers.

        It’s fair to favor those who are up to date (and therefore, favor the future users), not the ones who are not (which will hopefully be gone soon)

        July 22nd, 2012 at 14:19

        1. Jeremie Patonnier

          Yes, I agree with you.

          We will relay on JS to make our sites working. But even in modern browsers it’s kind of a flow design to assume that JS will always work as expected. It will not. There is plenty of reason for that :

          Network issue that prevent the script to be properly loaded
          Bugs in the script itself
          Conflict with third party scripts
          Conflict with browsers extensions
          and many more I can’t imagine ;)

          So even in modern browsers there is cases where your site or application will break. That doesn’t mean we should do everything possible to have our application working without JavaScript. No, it just means that we have to handle errors and in some cases (but not all cases) this errors handling is just finding a way to do the same as with JavaScript but without it.

          The problem here is that there isn’t a single response. Everyone has to find it’s own awnser depending on it’s own project context.

          July 22nd, 2012 at 14:44

  4. Paul Miller

    Frederico, Jeremie, I think you’re both partially right. When I’m building a site, I want to use as few js scripts as possible. Using CSS properly can solve 90% of our problems with support, so long as we cascade properly. However, for that 10% where it may not even be a CSS related issue, and often, where functionality of HTML5 is involved, a polyfill may be completely necessary.

    I think the background color example was a poor choice to argue a point over this, however. If you wanted a solid color in old browsers without RGBa support, and a transparent color in newer browsers with RGBa, you should just do this:

    div {
    background-color: #333;
    background-color: rgba(0,0,0,.8);
    }

    or, if you’re going to be getting crazy with these, make a duplicate rule (for ie7 or ie6’s sake:

    div {
    background-color: #333;
    color: #FFA500;
    }

    div {
    background-color: rgba(0,0,0,.8);
    color: rgba(255,255,0,.5);
    }

    All css; no js needed.

    July 19th, 2012 at 22:14

    1. Federico Brigante

      Obviously the rgba problem can (and should) be solved without Modernizr, but many others can’t (hence the existence and popularity of Modernizr), so just replace “rgba” with “<most Modernizr-supported features>” (e.g. transforms?) and my solution should still be valid.

      July 22nd, 2012 at 14:22

  5. Jhon St

    Everybody should write articles like yours, to the point, in a simple not pretentious lenguage, without superfluos extra content and with simple examples to grasp the idea. Thank you.

    July 20th, 2012 at 16:10

  6. ionut popa

    Hi Guys,
    I think the rgba problem can also be handled this way without the use of javascript.

    div {
    background : #333;
    background : rgba(0,0,0,.8); //browsers that don’t understand this will skip it
    }

    And also, what is the use case of dealing with css prefixed properties in JS? Usually from javascript we apply/toggle a class for html elements not add properties. (Modernizr.prefixed(“transition”))

    August 28th, 2012 at 08:24

    1. Jeremie Patonnier

      “Usually from javascript we apply/toggle a class for html elements not add properties.”

      You’re right, it’s definitely best practice.

      August 28th, 2012 at 15:01

  7. purple leaves

    This sounds unbelievable.

    its a lot of special work, checking every possibility.
    But its definately worth it for the result. E.g. the rgba – functionality in html5/css3 is great. So i would test if rgba exists, if not, then ill just use jquery animate? That should be possible no problem, right?

    Greetings

    November 2nd, 2012 at 09:56

  8. Thomas

    Progressive enhancement and Graceful Degradation –

    Is Progressive enhancement and Graceful Degradation not, two sides of the same coin?

    I think correct me if I am wrong – Progressive enhancement is one pattern to use and Graceful Degradation is another one. E.g see here on wikipedia:

    http://en.wikipedia.org/wiki/Progressive_enhancement

    I think you have to make a rewrite somewhere sorry to be the one to say so
    : )

    I mean it constructive we all get things wrong sometimes. Maybe it is just me.

    Greetings ; )

    November 11th, 2012 at 02:55

    1. Jeremie Patonnier

      Hi!

      Well, FWIW in my opinion Progressive Enhancement and Graceful Degradation, in a web design context, are the same things with a matter of perspective. With Progressive Enhancement, you work for average browsers and make sure cutting edge browsers will benefit about new modern things; With Graceful Degradation, you work for average browsers and make sure legacy browsers will render something functional. So, it’s always about being future proof and backward compatible… which is the whole story of the web since its beginning ;)

      To me it’s not possible to do Progressive Enhancement without doing Graceful Degradation at the same times, because there is always a legacy browser, an average browser and a cutting edge browser somewhere. And worst, in some cases, what you define as an average browser can be a legacy browser or a cutting edge browser in another context. So, I disagree to say that those 2 patterns are different, they are the two part of the same global pattern.

      Cheers :)

      November 11th, 2012 at 10:47

      1. Thomas

        Yeah but with gracefull degradation you are not taking care of old browsers. You build for new browsers and hope that the page will degradate gracefully.

        With progressive enhancement you build for a majority of browsers to make sure the page will render nicely. And than you make sure which features the browser supports or not. And use these features if the browser supports it.

        So I do belive they are kind of different. They attack the same problem.

        But I know what you mean. And if I was unclear before – I think your article is good ; )

        Cheers :)

        December 5th, 2012 at 05:46

Comments are closed for this article.