Skip to main content

Using the Modernizr library to provide graceful degradation for older browsers

So in my last blog post, Using the sass @for directive to generate staggered :nth-child transitions, I mentioned that the latest couple of websites I have been working on have been focusing on supporting more modern browsers and using progressive enhancement​ so that older browsers still have the same functionality - without the flourish.

So speaking of progressive enhancement, one of the most useful tools that can help you provide logical, functional fallbacks for browsers that don't support CSS3 and HTML5 features is Modernizr.

What is Modernizr?

Modernizr is a small JavaScript library that detects the availability of native implementations for next-generation web technologies, i.e. features that stem from the HTML5 and CSS3 specifications.

Modernizr uses feature detection to discern which CSS3 and HTML5 features the user's browser supports. Classes are then added to the <html> element of the page, giving us a way to apply different styles based on this.

For example, if the user's browser supports border-radius, the <html> element will have the class borderradius added, if not, the no-borderradius class will be added. Pretty simple - pretty cool.

Adding it to your Drupal website

To add Modernizr manually, the first thing you need to do is download the development version of the Modernizr library for their site (when you’re ready for production, you can use the build tool on their download page to pick only the tests you need).

Now you need to make sure it gets added to your pages. I usually like to add the library to my theme and include it in my .info file this way my theme will add it to every page for me.

I generally use the Omega base theme and I put Modernizr in its own folder within the libraries folder that omega creates for me:

sites/all/themes/THEMENAME/libraries/modernizr/modernizr.js

And then add the following to my THEMENAME.info file:

scripts[] = libraries/modernizr/modernizr.js

You could alternatively use the Modernizr Drupal module, though, if I'm honest, I don't have much experience with that.

How can I use it to provide graceful degradation?

So now we have Modernizr adding the classes we need to identify the browser's capabilities - we need to put them to use. While the border-radius example above is nice and simple, it actually isn't that useful as a browser that doesn't support border-radius will automatically fall back to just not using it - which is fine in my opinion: rounded corners are a privilege, not a right.

A better example is probably something like CSS generated content (:before and :after) or CSS transforms. Let's use generated content as an example - imagine we are building a button with some kind of icon in it. Using sass, we might do something a bit like this: 

.my-cool-button {
  display: inline-block;
  position: relative;
  background: tomato;
  padding: .5em 3em .5em 1em;
  &:after {
    content: '>'; // imagine this is an icon..
    position: absolute;
    top: .5em;
    right: 1em;
  }
}

So that's pretty sweet, we have a button with an icon using the :after pseudo element. The problem with this code however,  is that on browsers that don't support CSS generated content we will just have a button with too much padding on the right and no icon. That's where Modernizr can help us out.

I'm going to go ahead and assume that the icon is purely decorative, and a graceful fallback would be to just remove it, and the padding on the button.

.my-cool-button {
  display: inline-block;
  position: relative;
  background: tomato;
  padding: .5em 3em .5em 1em;
  &:after {
    content: '>';
    position: absolute;
    top: .5em;
    right: 1em;
  }

  // Where the magic happens!
  .no-generatedcontent & {
    padding: .5em 1em;
  }
}

This will give us the following CSS - you can see that our fallback style will be more specific than the default style and override it only for browsers that don't support generated content:

.my-cool-button {
  display: inline-block;
  position: relative;
  background: tomato;
  padding: .5em 3em .5em 1em;
}
.my-cool-button:after {
  content: '>';
  position: absolute;
  top: .5em;
  right: 1em;
}
.no-generatedcontent .my-cool-button {
  padding: .5em 1em;
}