Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Feature Detection With Modernizr for Cross-Browser Compatibility

DZone 's Guide to

Feature Detection With Modernizr for Cross-Browser Compatibility

We dive into the workings of the Modernizr framework, a great choice in the dev's tool kit for cross-browser compatibility.

· Web Dev Zone ·
Free Resource

Modernizr is an open source and compact JavaScript library that allows developers to craft various levels of experiences for users with respect to cross-browser compatibility. Modernizr helps developers to perform cross-browser testing to check whether new the generation of HTML5 and CSS3 features are natively supported by their visitor’s browsers or not and to provide dedicated fallbacks for older browsers that are notorious for their poor feature support. Modernizr coupled with the principle of progressive enhancement helps to design cutting-edge websites layer by layer, taking advantage of powerful modern web technologies without discarding users that are still using older browsers like IE.

How Does Modernizr Work?

Modernizr was launched in July 2009 by Faruk Ateş to battle cross-browser compatibility issues in a uniform, standardized manner. Today, Modernizr as feature detection library is one of the most popular JavaScript libraries, offering more than 270 tests, and is being used in 8.76% websites globally (half a million websites in the US alone). Instead of relying on highly untrustworthy browser detection methods using “User-Agent” sniffing, Modernizr is, instead, based on feature detection. While browser detection is centered around the question “what browser is the visitor using?” feature detection revolves around the question, “what features are supported by the visitor’s browser?” Modernizr runs a series of JavaScript-based feature detection tests in a user’s browser to check for cross-browser compatibility for HTML and CSS by allowing you to target each browser's functionality separately.

For feature detection, Modernizr performs three basic functions:

  • Adds classes indicating feature support, which can be used to conditionally apply CSS styling rules to different elements.
  • Creates a JavaScript object to check or validate support for any HTML or CSS feature in a browser.
  • Allows devs to conditionally supply custom JS scripts or polyfills to imitate lacking features.

It’s important to remember that feature detection with Modernizr can only detect which features are supported. It cannot provide functionality for those unsupported features in an older browser. This is achieved by “polyfilling” which we will discuss later in this blog.

I have also written another blog which represents the use of @support feature queries to perform CSS feature detection for cross-browser compatibility.

Setting Up Modernizr for Feature Detection

1. In order to perform feature detection with Modernizr, you need to add the Modernizr.js file to your project. This can be done in two ways:

  • Download from the website: Visit the official website to build and download the JavaScript file. Click on “Add your detects” to handpick the features that you want according to your project’s needs or click on “development build” to be redirected to the build page with all the tests/detects options pre-selected. Click on the build button to download the file.imageimage
  • Using npm and command line: Modernizr can also be installed using node package manager or npm. You can install npm here. After installing npm, open the command line and enter: npm install -g modernizr

2. Now include the downloaded Modernizr file in the section of your page.

<script src="modernizr-custom.js"></script>

3. Add “no-js” class to the <html> tag.

<!DOCTYPE html>
<html class="no-js"> 
<head> 
<script src="modernizr-custom.js">
</script> 
</head>

This no-js class is a necessary fallback if the user has disabled JavaScript in their browser or the browser itself does not support JavaScript. Once the page is loaded, and in case that the browser supports JavaScript, the no-js class will be replaced by the js class automatically by the Modernizr for feature detection.

4. Modernizr adds several CSS classes on the root <html> element. These classes are added based on the browser’s capabilities (feature/no-feature) – classes are added for features that are supported and classes are added with a no- prefix for features that aren’t supported.

For example, if Flexbox is supported by the browser, the flexbox class will be added to the <html> tag. If it isn’t supported, no-flexbox class is added instead.

Classes added to <html> tag by Modernizr for feature detection tests in IE9

<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">

CSS Feature Detection With Modernizr

These classes are added to the <html> tag by Modernizr for feature detection of CSS style properties based on whether a feature is supported by a given browser or not. Classes with the no- prefix will be automatically applied in browsers that do not support those corresponding features.

For example, if the box-shadow property is supported by a browser, then the boxshadow Modernizr class is added to the <html> tag. If it isn’t supported, then no-boxshadow Modernizr class is added instead. We can use just these two CSS classes to effectively target all browsers irrespective of their support for this particular feature. The .boxshadow class can be used to style box-shadow around a div with horizontal offset and vertical offset of 10px, blur of 8px, and spread of 15px for all the supported browsers and the .no_boxshadow class can be used to code a fallback with thicker border width to compensate for lack of any shadow for all the unsupported browsers.

.boxshadow #box {     
	border: 2px solid black;     
	-webkit-box-shadow: 10px 10px 8px 10px #888888;     
	-moz-box-shadow: 10px 10px 8px 10px #888888; 
}    
.no-boxshadow #box {     
	border: 5px solid black; 
}

Thus, instead of writing heaps of code to target individual browsers using User-Agent Strings, Feature detection with Modernizr reduces the task to coding just two blocks of code – one for compatible browsers and the other for incompatible ones.

Another example for CSS linear-gradients:

.no-cssgradients .header {   
	background: url("https://unsplash.it/640/425?image=44"); 
} 
.cssgradients .header { 
  background-image: url("https://unsplash.it/640/425?image=44"), linear-gradient(red, blue); 
}
  • Avoid class name clash - It is quite plausible that classes created by Modernizr can clash with a pre-existing CSS class that you would have added to your stylesheet. In order to avoid such a scenario, it is advisable to add a class prefix to all your Modernizr classes to make them completely unique. For example, you may already be using a class called ‘boxshadow’ which will clash with the detect class created by Modernizr by the same name. You can make use of class prefixes to easily address this problem. Make the following changes in your configuration- 
{
  "classPrefix": "foo-",
  "feature-detects": ["dom/boxshadow"]
}
  • Now instead of <html class="boxshadow">, modernizr will add <html class="foo-boxshadow">.
  • Prevent Modernizr from adding classes to HTML tag - If you want Modernizr to not add any of its classes to your HTML tag, set “enableClasses” to false in your config file. This still excludes the no-js class. To prevent even that, set “enableJSClass” to false as well.

JavaScript Feature Detection With Modernizr

As discussed earlier, instead of trying to detect the user’s browser using the unreliable and now defunct User-Agent string, Modernizr rather relies on feature-detection. Modernizr runs a series of JavaScript-based checks or tests in the background during page load to detect whether features are supported by the browser or not. These tests return a Boolean value “True” if a feature is supported and “False” is it isn’t. Using these Boolean results, it creates a JavaScript object called Modernizr. We can access various properties of this object ‘Modernizr’ for feature detection using Modernizr.featureName. For example, Modernizr.video will return “true” if the browser supports the video element, and false if the browser doesn’t.

Below is the syntax used for feature detection with Modernizr using JavaScript:

if (Modernizr.feature) {
 /* Rules for browsers that support this feature*/ 
} else{
  /* fallback for browsers that do not support this feature*/ 
}

The Modernizr object helps to validate the support for CSS as well as HTML features. This is where Modernizr offers a clear advantage over native CSS feature detection using the @supports feature queries. We can use this capability of Modernizr to code necessary fallbacks for important HTML5 elements like canvas, video, audio, and semantic elements like article, nav, header, footer, etc.

Following example shows how to test for CSS linear gradients using javascript and adding linear gradient class for browsers that support it.

$(document).ready(function () {       
	if (Modernizr.cssgradients) {         
		$('#box').addClass('cssgradients');     
	}              
	if (Modernizr.cssgradients) {         
	$('#box').addClass('no-cssgradients ');     
	}   
});

Apart from feature detection using JavaScript to test whether a browser supports that particular web technology or not, Modernizr can also be used for loading polyfills/shims to imitate the features that a browser lacks or does not support.

What Are Polyfills?

A polyfill is JavaScript code that acts as a fallback to imitate modern functionality in older browsers that natively do not support such features. For example, if you want to embed a video on your website, you would use the HTML5 <video> tag. This is compatible with every modern browser. However, older legacy browsers like Internet Explorer 8 and its previous versions do not support the <video> tag. To make sure that any user still using these browsers are not excluded from viewing such content, we use a popular polyfill called Embed Video Player. For Canvas, the most popular polyfill is FlashCanvas, for SVGs – svgweb, for audio – SoundJS, etc.

Loading Polyfills Using JavaScript

As discussed earlier, apart from performing JavaScript tests for browser support, Modernizr can also be used to conditionally load polyfill/shim scripts to provide functionality when a browser lacks feature support. This is achieved by the use of Modernizr.load() method.

Modernizr.load

The Modernizr.load method is a conditional loader based on an extremely popular yesnope.js library which loads JavaScript files based on the result of a feature detection test. For example, we can use the modernizr.load method to test for the availability of support for flexbox and load a polyfill if the browser does not support it.

If the browser supports flexbox, the flexlayout.css file will be loaded; but if there is a lack of support, the matchHeight.js polyfill will be loaded, which imitates the flexbox feature in older browsers.

Modernizr.load({
    test: Modernizr.flexbox,
    yep : 'flexlayout.css',
    nope: 'matchHeight.js' });

Modernizr.load() takes the property defining a feature as an argument and performs a test to check its support. If the property is supported and test succeeds, the “yep” case script is loaded. If the property isn’t supported and the test fails, the “nope” case script is loaded. If a script is to be loaded regardless of whether the test fails or not – “both” case. For example:

Modernizr.load({     
	test: Modernizr.canvas,     
	yep:  'Canvasavailable.js',   
	nope: 'FlashCanvas.js',     
	both: 'CustomScript.js' 
});

Modernizr.load() can also be used in cases where you want to create a fallback in case Google or Microsoft CDN networks are not accessible, which can wreck your entire webpage. Without CDN, the jQuery or Bootstrap scripts will not load if you included them using CDN links. The following example shows how to create a backup for loading jquery if CDN fails. It will first attempt to download jQuery from Google CDN, the use the function corresponding to “complete” case to check if jQuery is present or not. If jQuery is absent because it couldn’t be downloaded from Google CDN, “load” case will load the backup jQuery from your local storage

Modernizr.load([
    {
        load: '//ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js',
        complete: function () {
            if (!window.jQuery) {
                Modernizr.load('js/libs/jquery/3.3.1/jquery.min.js');
            }
        }
    },
    {
        // execute this if jquery couldn’t be loaded.
        load: 'backup-jquery.js'
    }
]);

Modernize.load AND yesnope.js Deprecated

NOTE: Modernizr.load and yesnope.js have now been deprecated and no longer supported by the current version of Mmodernizr(v3.5). You can still use this in v2.8. You can read more about the deprecation notice addressed by the creator of Modernizr here.

A viable alternative now is to use the jQuery getScript() method. Following example shows how to load a polyfill script if a browser does not support feature detection:

if (Modernizr.geolocation){
  //feature is supported by the browser
  console.log('geolocation supported');
} else {
  // feature not supported - load polyfill
  $.getScript('path/script.js')
  .done(function() {
    console.log('script loaded');
  })
  .fail(function() {
    console.log('script failed to load');
  });
}
Topics:
wbe dev ,cross-browser compatability ,modernizr ,css tutorial ,javascript tutorials

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}