Getting Started on Line-of-Business HTML5 App – Part 4 Using Modernizr, Polyfills, YepNope

imageModernizr is a small JavaScript library that you can use for feature detection, browser compatibility using polyfills, and quick JavaScript loading. I’ll take each one in turn.

It detects the availability of native implementations for next-generation web technologies, i.e. features that stem from the HTML5 and CSS3 specifications. Many of these features are already implemented in at least one major browser (most of them in two or more), and what Modernizr does is, very simply, tell you whether the current browser has this feature natively implemented or not.

Once you do the feature detection for your browser, you can then do polyfill. Polyfills is a term coined by Remy Sharp to describe JavaScript shims that replicate the standard API found in native features of new browsers for those without such features – are a way of helping us achieve this.

And by using Modernizr.load, you can load your CSS and JavaScript resources side-by-side with Modernizr. It’s optional in your build, but if you are loading polyfills, there’s a good chance it can save you some bandwidth and boost performance a bit.

Why Feature Detection

Let’s start with the idea that all browsers are not created equal. As browser vendors raced to become dominant, most implemented the features that were in high demand, even if they weren’t yet standardized. So features and implementations differ between browsers. For those professionally developing Web pages, this is a fact of life.

One approach to handling differences among browsers is to use browser detection. The most common way to do this is to use JavaScript to query the user-agent header:

 <script type="text/javascript">
 if ( navigator.userAgent.indexOf("MSIE")>0 ) {  
     // Run custom code for Internet Explorer. 
}
</script>

There are problems with this approach, it bundles multiple assumptions about the features the browser supports in one check. A single wrong assumption can break the site. And even if it works with today’s version of a browser, the next release might not require—or worse, might remove support altogether.

A far better approach to handling differences among Web browsers is to use feature detection.

There are two very important recommendations to keep in mind when using feature detection:

  • Always test for standards first because browsers often support the newer standard as well as the legacy workaround.
  • Always target only related features in a single check, effectively minimizing assumptions of a browser’s capabilities.

The name Modernizr comes from the team goal of modernizing our development practices. 

Modernizr has built-in detection for most HTML5 and CSS3 features that’s very easy to use in your code. It’s very widely adopted and constantly enhanced.

Here’s an example of Modernizr detecting whether your browser supports fontface.

 <script type="text/javascript" src="modernizr.custom.89997.js"></script>

<script type="text/javascript">
    if(Modernizr.fontface){
        // font-face is supported
     }
</script>

About Shims, Polyfills

Modernizr still pairs extremely well with scripts that do provide support when native browser support is lacking. These come in the form of CSS and JavaScript libraries or sometimes even as Flash or Silverlight controls that you can use in your project, adding missing HTML5 features to browsers that don’t otherwise support them.

The difference between shims and polyfills is that shims only mimic a feature and each has its own proprietary API, while polyfills emulate both the HTML5 feature itself and its exact API.

There is a polyfill for nearly every HTML5 feature that Modernizr detects, including:

  • SVG
  • Canvas
  • Web Storage
  • HTML5 Sectioning
  • Video
  • SQL
  • Web Forms
  • Web Sockets
  • Geo-Location
  • Browser State Management
  • File API/Drag and Drop
  • MathML
  • Cross-Origin Resource Sharing (CORS)
  • CSS Selectors, Transforms, Styles, Media Queries
  • Media Capture
  • and much more

And if there is one missing, you can create your own. See The Developer’s Guide To Writing Cross-Browser JavaScript Polyfills.

Loading Polyfills

Modernizr.load is a resource loader (CSS and JavaScript) that was made to specifically to work side-by-side with Modernizr. It’s optional in your build, but if you are loading polyfills, there’s a good chance it can save you some bandwidth and boost performance a bit.

There’s a lot that you can do with Modernizr.load. It was released standalone as yepnope.js but it was made specifically with Modernizr and feature-testing in mind. For the complete docs for Modernizr.load, see yepnopejs.com.

yepnope is an asynchronous conditional resource loader that's super-fast, and allows you to load only the scripts that your users need.

So yepnope function call maps to the same call as Modernizr.load.

Here’s a sample of what the load syntax looks like:

 Modernizr.load([{
  test : /* boolean(ish) - Something that you want to test */,
  yep  : /* array (of strings) | string - The things to load if test is true */,
  nope : /* array (of strings) | string - The things to load if test is false */,
  both : /* array (of strings) | string - Load everytime (sugar) */,
  load : /* array (of strings) | string - Load everytime (sugar) */,
  callback : /* function ( testResult, key ) | object { key : fn } */,
  complete : /* function */
}, ... ]);

So a simple example could be:

 Modernizr.load({
  test: Modernizr.geolocation,
  yep : 'geo.js',
  nope: 'geo-polyfill.js'
});

The load function is the core of yepnope.js. The recommended type for resources is an array of test objects. The consistency helps make your code look better and stay maintainable.

However, if you don't need more than one test group, as in the previous example, then you can avoid putting it in an array, and just send in the object.

In my example that I am building for my canvas drawing, I use the following code:

  1. First to load Modernizr (use the one with minin the filename).

     <script src="modrnizr-2.5.3.min.js"></script>
    
  2. And then to load jQuery and test for whether the browser supports canvas. If it does not, I load the excanvaspollyfill.

     <script>
            Modernizr.load([ {
                load: 'https://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.min.js',
                complete: function () {
                    if (!window.jQuery) {
                        Modernizr.load('../Scripts/jquery-1.6.1.min.js');
                    }
                }},
            {
                test: Modernizr.canvas,
                nope: '../Scripts/excanvas.js',
                complete: function () {
                    Modernizr.load('../Scripts/eventmap.js');
                }
            }]);
    
    </script>
    

Getting Started with Modernizr

Where to Get Modernizr

Get Modernizr:

You can download the latest version of Modernizr from within your project in Visual Studio. Right click the project, click Manage NuGet projects.

image

You will want the full version to use YepNope. (Modernizr listed first in by the NuGet does not include yepnope.)

Or you can download Modernizr from GitHub.

Add Modernizr to your Web page

Next, insert Modernizr script into the head of your Web page.

 <script src="modrnizr-2.5.3.min.js"></script>
Get Polyfills

Next, you can get your polyfills from GitHub.

And use Modernizr.load to test to do the right thing for your browser.

The Modernizr documentation is excellent with code examples and explanation of features.

Customize Modernizr

And if you are not testing every part of HTML5, you can customize Modernizr to select only the tests you need. So you need to test only for canvas, go to https://modernizr.com/download/ to create a customized version of Modernizr that tests only what you need.

image

How Modenizr Works

Once you’ve add a script reference to Modernizr in a page it’ll go to work for you immediately. In fact, by adding the script several different CSS classes will be added to the page’s <html> element at runtime. These classes define what features the browser supports and what features it doesn’t support. Features that aren’t supported get a class name of “no-FeatureName”, for example “no-flexbox”.

Features that are supported get a CSS class name based on the feature such as “canvas” or “websockets”.

In IE9, Modernizr will return this code in your html tag:

 <html class=" js no-flexbox canvas canvastext no-webgl no-touch geolocation postmessage no-websqldatabase no-indexeddb hashchange no-history draganddrop no-websockets rgba hsla multiplebgs backgroundsize no-borderimage borderradius boxshadow no-textshadow opacity no-cssanimations no-csscolumns no-cssgradients no-cssreflections csstransforms no-csstransforms3d no-csstransitions fontface generatedcontent video audio localstorage sessionstorage no-webworkers no-applicationcache svg inlinesvg smil svgclippaths">

It is a best practice to include a no-js attribute to your html tag. If JavaScript is enabled, no-js will be removed by Modernizr and a js class will be added along with other classes that define supported/unsupported features.

 <html class="no-js">

Modernizr with CSS

You can use the CSS classes added to the <html> element directly in your CSS files to determine what style properties to use based upon the features supported by a given browser.

For example, the following CSS can be used to render a box shadow for browsers that support that feature and a simple border for browsers that don’t support the feature:

 .boxshadow #MyContainer {
    border: none;
    -webkit-box-shadow: #666 1px 1px 1px;
    -moz-box-shadow: #666 1px 1px 1px;
}
    
.no-boxshadow #MyContainer {
    border: 2px solid black;
}

More Information on Modernizr, Polyfills

For more information, see:

Next Up

Let’s use Modernizr in drawing something on a <canvas> tag.

 

Bruce D. KyleISV Developer Evangelist | Microsoft Corporation

image