Using Modernizr to detect HTML5 features and provide fallbacks

Modernizr is a JavaScript library that detects which HTML5 and CSS3 features your visitor’s browser supports. In detecting feature support, it allows developers to test for some of the new technologies and then provide fallbacks for browsers that do not support them. This is called feature detection and is much more efficient than browser sniffing.

Modernizr is very useful for detecting CSS3 support, but this article will focus on HTML5. The principles are essentially the same, though.

It’s important to note that Modernizr doesn’t “fill in the gaps” (i.e., polyfill) for you. It only detects whether something is supported. But you can use Modernizr as part of the polyfilling process.

Versions of IE8 and below do not recognise new-in-HTML5 elements by default, so you have to fix this with some JavaScript. You could possibly create each of these yourself with the below code, or you might use the HTML5 Shiv by @rem, which includes all the new elements.

You can see in the code above that you need a modernizr.js file. You have to build and download this yourself by choosing the features you want to detect. Do this by choosing the ‘Production’ option in Figure 1 and then ticking the necessary options in Figure 2. This helps keep the file size down by not detecting everything Modernizr is capable of. There is a development version (see Figure 1) that you can link to whilst developing your site, but before you put the site live, you should build the production file you need.

Also notice the second line of the HTML above: there is a no-js class on the <html> element. Modernizr first removes this and replaces it with a js class, which could be useful in your CSS. Along with the js class, it adds classes for all the features the browser supports and for the features it does not support, pre-fixing those with no-.

Modernizr creates a global Modernizr JavaScript object, which allows us to query different properties of that object to perform feature detection by calling Modernizr.<featurename>. So to test for canvas support, you would write the following:

So try this page in a modern browser and there will be a nice message for you.

Because you’re all good developers and write unobtrusive, progressive JavaScript so that everyone can use your site, you also want to check if canvas is not supported. You have a couple of options here. You could use the above if statement along with an else statement, like so:

In the examples above, you’ve seen the simplest way to detect a browser feature. What if you wanted to detect a feature and use a polyfill to make the browser perform better? You can do this with YepNope.

YepNope is a conditional loader, which means it will only load the scripts that are needed by the browser. And it’s built into Modernizr, so you don’t have to worry about downloading and linking to another JavaScript file.

So how do you use it?

Using canvas as an example again, you’ll generally want a fallback for non-supporting IE8 and below. The usual way of doing this would be to link to a JavaScript polyfill, such as FlashCanvas in your HTML:

<script src="http://flashcanvas.net/bin/flashcanvas.js"></script>

The problem with this approach is that all browsers will download this script. That’s unnecessary and should be avoided where possible. You could arguably wrap the <script> element in conditional comments, but if you can keep the files out of the markup altogether, then you should. You can do this using Modernizr.load(). Modernizr has YepNope built into it, so you can easily test for a feature and then supply a polyfill.

So let’s take a look.

You should note that .load() is not included in the development file by default. You need to include it and build it yourself.

The basic use of the .load() function allows you to test for a feature and ask whether it’s true (yep) or false (nope). In this example, Modernizr tests for canvas support, and if the feature doesn’t exist, then it loads FlashCanvas:

This test looks for <input type="date"> support. When it fails, it loads in the two external jQuery JavaScript files and a local CSS file. (Our tests suggest that the CSS file needs to be local.) Once it’s done that (i.e., on complete), it then calls the plugin for each <input type="date"> in the DOM. In most browsers, the jQuery will be loaded (Figure 6), but in Opera, the files aren’t loaded because it has a native calendar control (Figure 7):

Modernizr is a powerful feature detection library. It allows you to check whether a browser supports various features and, depending on what you want to achieve, lets you use a polyfill. This article looked at how to generate a Modernizr JavaScript file and examined two different ways of using Modernizr: directly using the Modernizr object (Modernizr.<featurename>) and then using the built-in YepNope.

So, what do you think? Let us know in the comments below!

Category

Tags

Translations

This article was written by Tom Leadbetter. Tom is a designer/frontend web developer based in Liverpool, UK. He is football (soccer) mad, loves gaming and other geeky bits n bobs. Stalk him on Twitter.

24 Responses on the article “Using Modernizr to detect HTML5 features and provide fallbacks”

Is it also possible to serve JavaScript/jQuery fallbacks for certain CSS3 properties with Modernizr load?

For instance I use the ‘background-size’ property set to ‘cover’ for some background images. For IE8 and below I do some UA sniffing and inject the background images as img tags (class=”background”) with jQuery into the DOM.

But I can only do my fallback like this for the old IE and not for the other older browsers that don’t support the background-size property, so can I use Modernizr load for this instead of UA sniffing?

Modernizr is a great tool, but we must not forget that any page that relies on Modernizr to work, will not work at all in Browsers where Javascript is not activated.

It is of course possible to state that Javascript is so essential today, that we can completely disregard those that turn it off. It might even be correct, but I’m amazed that there is so little discussion about that important point nowadays.

Has the web developer community already made the decision, that there is no need to think about users that don’t have Javascript activated? (It does seem CSS support is already treated that way.) Does anyone ever test their pages with Javascript turned off these days? Do we need to?

@Bertil Wennergren
You will have to add a no-js class to the HTML tag and than Moderniizr detects if a browser supports javascript or not. If yes, it replaces the no-js with js. If not it stays no-js. With no-js you can create the fallback solutions for non javascript users/devices in your CSS. The user experience will be not that great, but the site is still usable and the content is still 100% accessible.

“but the site is still usable and the content is still 100% accessible”

Not if you don’t actually test in e.g. MSIE6-8 with Javascript deactivated. How many actually do that? Sometimes new HTML5 elements will not result in a usable page in MSIE6 witout Modernizr or the Shiv.

Thanks for article , Im glad to see Chrome is now the most popular browser and IE9 is being rolled out on new systems. The days of IE7-IE8 will soon be a thing of the past but in the meantime this tool works great.

Anyone who is browsing the web with a browser capable of javascript, yet with it turned off, is either a retard, or is using that computer for something that would end in them not visiting random websites…

Every device nowadays supports javascript, so you can count on javascript being enabled for your site… or your site is for retards… either way…

The web runs on Javascript and has run on Javascript since the early 2000’s. If someone has their Javascript turned off, they have essentially turned off the web altogether. Might as well turn of CSS and HTML while you’re at it. I don’t waste my time testing for turned off JS.

While testing for compatibility with SCREENREADERS is related, it is not the same thing as testing for people who have turned off JS

I think at this point, anyone who deliberately turns off Javascript deserves exactly what they get. My belief is there is not enough tinfoil in the world for the hats of those who browse the internet with Javascript turned off and certainly those people aren’t visiting the websites I develop.

I’m VERY excited by this article, planning to try your example of loading JQuery within Modernizer after previous failed attempts.
Please clarify about the “Modernizer is same as Yepnope” statement, which I see oft repeated. Specifically I want to know about your example of yepnope properties – I see the same switch of reference in every tutorial – can I use “modernizer” instead of “yepnope” with those property patterns in Modernizr?
(Is “modernizr ([{ callback:” OK to use?)
Are the two names the same thing within Modernizr? I cannot be sure whether you are saying to load the yepnope program or to use “yepnope” as part of the modernizr syntax? Please nail this down.
Another thing that I cannot find is an example of combining two javascript polyfills within one “script.js” file. Mr. Doubting Thomas here wants to SEE how it looks. Every tutorial skips ahead to “too hard to do so use a Concatenator / minifier” and skips over this critical bit of information.
The third big bit of info that I’m wondering about is about the path to polyfills to call within Modernizr. If I combine multiple polyfills into one scripts.js file, do I just call that one scripts.js file for every time I need a polyfill? Wouldn’t that load the entire scripts.js file multiple times? Or should I not combine/minify scripts when using Modernizr and just keep each one separate?

I just set up a couple of demos to test the example code, and I ran into a problem with Modernizr 2.6.2 and the latest version of Chrome. The complete callback of Modernizr.load is called regardless of the test results. This causes an error when jQuery is not loaded, so I have two alternatives to the example you posted:

Hello, first sorry for my English, I’m working on a web application, the case problem is I have a date with the guy in the safari browser. I need to be in date format (dd-mm-yyyy), and tested with the example of your article but I can not move, so I ask for help if you can help me with this. Thanks in advance.