Skip to main content

Start your project right with Modernizr

Modernizr is a popular feature-detection JavaScript library that, since 2010, has helped web designers and developers take advantage of HTML5 and CSS3 despite uneven cross-browser support. It won .net’s Open Source App of the Year in 2011 and is packaged in the popular HTML5 Boilerplate so it’s fair to say that it is included on many websites going into production today.

Most tutorials that cover the basics of using Modernizr simply show the syntax and don’t discuss when and why you would use it in a project. Because of this many web designers don’t use the library to its full potential and aren’t aware of the ‘extras’ the library includes by default.

Modernizr offers four major features that are useful to web designers:

  • Feature Detection: Capability specific CSS-Class Injection
  • Feature Detection: Javascript Object
  • Modernizr.load();
  • HTML5Shim

At its core, Modernizr tests what HTML5 and CSS3 features are supported by the current browser and makes this information available via injecting classes on the HTML element and through a JavaScript object.

Feature detection: CSS class injection

When loaded, Modernizr tests the client browser's HTML5 and CSS3 capabilities and injects classes on the HTML element that reflect the features supported by that browser. This enables you to style elements differently based on what features are supported.

So, for example, when the latest version of Chrome pulls up a page that loads Modernizr the HTML element looks like this:

<html class="js no-touch postmessage history multiplebgs boxshadow opacity cssanimations csscolumns cssgradients csstransforms csstransitions fontface localstorage sessionstorage svg inlinesvg blobbuilder blob bloburls download formdata">

Compare that with the HTML tag from the same page loaded in Internet Explorer 7:

<html class="js no-touch postmessage no-history no-multiplebgs no-boxshadow no-opacity no-cssanimations no-csscolumns no-cssgradients no-csstransforms no-csstransitions fontface localstorage sessionstorage no-svg no-inlinesvg wf-loading no-blobbuilder no-blob no-bloburls no-download no-formdata">

Using the injected classes

Now that we can access which features are supported, what do we do with that information?

For starters, we can address the differences in the CSS by taking advantage of the classes injected on the HTML element:

.opacity .button {background:#000;opacity: 0.75;}.no-opacity .button {background: #444;}

Having this available at your disposal is great and can provide a solution for some complex styling problems that might arise. However, this is best employed sparingly and not as a primary method for accommodating older browsers.

Problem: can get messy

Since each CSS rule is essentially targeted at the support or non-support of a certain feature, your stylesheet could end up looking like this:

.button{//base styles}.boxshadow .button{//apply box shadow }.textshadow .button{//apply text shadow }.opacity .button {//add opacity}.no-opacity .button {//without opacity we might want to do something different}

Carried out through an entire stylesheet, this is going to get unruly.

Problem:reliance on JavaScript

Additionally, relying on CSS selectors that are dynamically generated by Modernizr increases your website’s exposure in case the script fails to load or the user has JavaScript turned off. While the subset of users that have JavaScript disabled is small, there are other cases where a script may not be executed.

Whether to use “.no-feature” or “.feature”

Depending on your preference for catering to older browsers or targeting newer ones, you might prefer to use selectors for missing functionality (i.e. .no-opacity) instead of existing functionality (i.e. .opacity). This way, if, for whatever reason, Modernizr doesn’t load, you don’t end up crippling your website in perfectly good and modern browsers.

.box{ //Fake box shadows for old browsers border-right: solid 2px #444; border-bottom: solid 2px #444;}.boxshadow .box{ border:none; box-shadow: 10px 10px 5px #888;}

In the above example, if Modernizr doesn’t load, the boxshadow class won’t be added and the fake box shadow is going to show in all browsers new and all.

.box{box-shadow: 10px 10px 5px #888;}.no-boxshadow{border-right: solid 2px #444;border-bottom: solid 2px #444;}

Here, if Modernizr doesn’t load, at least the correct style will be applied in newer browsers, which will typically be used by a majority of users.

Use fallbacks when possible

In many instances you can take advantage of CSS3 properties while specifying a fallback simply due to the fact that older browsers will ignore unsupported declarations. This obviates the need to apply styles using the classes injected by Modernizr.

#container{background: #EEEEEE; //Browsers that do not support BG gradientsbackground: linear-gradient(to bottom, rgba(0,0,0,0.65) 0%,rgba(0,0,0,0) 100%); // W3C}

Many browsers, many experiences

A user is generally only going to see your website in one browser, so as long as the experience is reasonably good in each one, there’s no reason they need to be identical. If an older browser can’t execute a particular CSS declaration you might simply live with it.

So perhaps if users with IE 6-8 don’t see the subtle curved border of your nav items you might consider addressing it with a shrug instead of a workaround.

#nav li{ Border: solid 1px #333; Border-radius: 3px;}

When you might want to use the classes

However, there are a couple of cases where you would want to take advantage of the injected classes:

1. If the fallback style doesn’t work

For example if you were to apply background:#000; opacity: #.25, a browser that doesn’t support the opacity feature would display a black background, whereas a solid but light gray background (#ccc) might be closer to the intended effect in the absence of opacity support.

#container{background:#fff; opacity: 0.25;}.no-opacity #container{background:#ccc;}

2. If the changes are minor and truly feature specific

For example, hiding drop down arrows on navigation on touch screen devices:

.touch .nav li.dropDown{ background:none; }

Cross-browser styling: use cascading IE classes

For general cross-browser CSS correction use conditional comments to set IE-specific classes on the HTML element to do the heavy lifting of cleaning up the appearance of older browsers (i.e. Internet Explorer v6-9).

This method is close to what you’ll find in the HTML5 Boilerplate and allows you to set rules for specific versions of IE in a manner that applies to each lower version browser. Often, but not always, CSS corrections applied at higher versions of IE fix similar issues present in lower versions.

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

Feature detection: JavaScript object

On load, the library creates a JavaScript object named Modernizr with the test results available as boolean properties.

Modernizr.geolocation; //True in Chrome, False in IE7Modernizr.cssgradients; //True in Chrome, False in IE7Modernizr.fontface; //True in Chrome, True in IE7

This can be useful directly in your code:

if (Modernizr.canvas){ // Create canvas object and get drawing} else { // Guess we're going to have to do something else.}if (Modernizr.localstorage){ // Go right ahead as planned sir} else { // Local Storage isn't supported, going to have to try something else}

It can also enable you to provide a more usable experience to, for example, touch screen users.

Given that hover effects don’t really fly with most touch enable devices, it usually makes sense to provide a differentiated experience. A simple example would be where content is delivered through hover:

if (Modernizr.touch){ $('.rolloverCaption').css('display', 'block');} else {$('.rolloverCaption').css('display', 'none').hover(function(){$(this).fadeIn(300);$(this)fadeOut(300);})};

For desktop browsers, content and navigation can sometimes be delivered through hover events.

For desktop browsers, content and navigation can sometimes be delivered through hover events.

For touch devices:

With touch devices, the hover event cannot be relied upon

With touch devices, the hover event cannot be relied upon

Based on the availability of a certain feature, such as localStorage, you may be required to implement very different solutions. In that case, it may make sense to dynamically load a .js file based on whether the browser supports localStorage. This is easy to do using Modernizr.load().

Modernizr.load() otherwise known as yepnope.js

yepnope.js is an asynchronous conditional resource loader that was specifically designed for and integrated with Modernizr. This simply means that yepnope.js will load scripts like JavaScript and CSS files in the background based on a given condition or set of conditions such as the browser supporting touch screen functionality or canvas. The syntax is intuitive, and you can use either the Modernizr.load() or yepnope.js to call the function. The following is equivalent:

Modernizr.load({ Test : Modernizr.localstorage, Yep : 'localstorage.js', Nope : 'localstorage-alternative.js'});yepnope({ Test : Modernizr.localstorage, Yep : 'localstorage.js', Nope : 'localstorage-alternative.js'});

If the “test” evaluates true (i.e. the browser support local storage), then localstorage.js will be loaded, otherwise localstorage-alternative.js will. “Yep” and “Nope” are optional, so you can just use one:

Modernizr.load({ Test : Modernizr.touch, Yep : ['js/touch.js', 'css/touch.css']});

Modernizr.load/Yepnope.js is a speedy and lightweight script loader that you’re already getting when you use Modernizr. For many projects yepnope.js is going be just fine. For a good comparison of the most popular script loaders – RequireJS, Yepnope, and LABjs – with the creator of Yepnope, check out this article.

Using modernizr.load() to "patch" the browser: shims and polyfills

Shims are bits of code that we can pull in that emulate or replicate missing browser functionality. Polyfills are a specific class of shims that aim to replicate that functionality exactly.

Using Modernizr.load(), if a browser doesn’t support a crucial CSS or HTML feature we can load alternative styles and/or JavaScript. From there we can correct the problem, provide an alternative, or push the user to a “Browser Not Supported” page.

At the moment, the best and most comprehensive list of individual polyfills is up on GitHub. However, the list is not curated for quality and includes many polyfills and shims that are in development, buggy, and sometimes, just don’t work at all.

Using the polyfill library: webshims lib

The Webshims Lib is a promising collection of various shims that can be loaded as needed. It’s one of the more comprehensive attempts at fully “patching” older browsers to conform to modern standards. Using Modernizr, it only loads shims as needed. It doesn’t attempt to shim every feature but some of the highlights are: canvas, HTML5 forms, HTML5 mediaelements, geolocation, and JSON-storage. See here for more details.

The Webshims Library is a promising ‘multi-shim’ that adds HTML5 functionality as needed

The Webshims Library is a promising ‘multi-shim’ that adds HTML5 functionality as needed

Taking Advantage of HTML5Shim

Older verisons of IE don’t allow for styling elements that it doesn’t recognize, such as semantic elements like <article> and <section>. However, there’s a workaround that HTML5Shim uses.

HTML5Shim is to Modernizr as fluoride is to drinking water – it’s a little bonus added to something you’d use anyway. Basically it’s just a shim that’s included by default with Modernizr that allows you to use HTML5 semantic elements in browsers that don’t support them.

Thank you for reading 5 articles this month* Join now for unlimited access

Enjoy your first month for just £1 / $1 / €1

*Read 5 free articles per month without a subscription

Join now for unlimited access

Try first month for just £1 / $1 / €1

The Creative Bloq team is made up of a group of design fans, and has changed and evolved since Creative Bloq began back in 2012. The current website team consists of six full-time members of staff: Editor Kerrie Hughes, Deputy Editor Rosie Hilder, Deals Editor Beren Neale, Senior News Editor Daniel Piper, Digital Arts and Design Editor Ian Dean, and Staff Writer Amelia Bamsey, as well as a roster of freelancers from around the world. The 3D World and ImagineFX magazine teams also pitch in, ensuring that content from 3D World and ImagineFX is represented on Creative Bloq.