Andi Smith

Modernizr Prefixed

There was a new release of Modernizr yesterday (2.5.1), and included within this release was some brand new features to the Modernizr Prefixed() API (introduced in 2.0), which can take away some of the pain of vendor prefixes from your JavaScript.

As you are probably aware if you are working with the latest JavaScript APIs and CSS3 technologies available in the browser, these are normally prefixed with a browser vendor tag. The reason for this is usually due to the feature still being in the experimental stage. As a simple example, if we wanted to scale an element on our page (and make it work cross-browser) we would have to write the following CSS:

#myElement {
  -moz-transform:scale(2); /* Firefox */
  -ms-transform:scale(2); /* IE (9+) */
  -o-transform:scale(2); /* Opera */
  -webkit-transform:scale(2); /* Safari and Chrome */
  transform:scale(2); /* One day someone will use this so let's keep it future proof */
}

It's a lot of code to scale an element, and there are various arguments on the web about why vendor prefixes are and are not bad; and there are even some solutions to avoid having to write this amount of CSS, such as Lea Verou's -prefix-free or using a class file in LESS.

But there are other problems which cannot be resolved so easily, such as vendor prefixes in JavaScript. These are used for the same reason as in CSS, but there are some implementation differences - these prefixes are not hyphenated and they are case sensitive.

$('#myElement').on('click', function() {    
    var transform = 'scale(2)';

    this.style.MozTransform = transform; /* Firefox */
    this.style.msTransform = transform; /* IE (9+) - note ms is lowercase */
    this.style.OTransform = transform; /* Opera */
    this.style.WebkitTransform = transform; /* Safari and Chrome */
    this.style.transform = transform; /* One day, my pretty */    
});

But that's a lot of code.. It makes checking for a particular event or piece of JavaScript functionality a total pain - and this is where Modernizr Prefixed comes in.

Modernizr Prefixed to the Rescue

Modernizr

Modernizr.prefixed(str)

At its simplest, Modernizr Prefixed allows us to find the relevant prefix for the browser the user is currently visiting your page on - which is the only browser we need to care about at runtime. For example, to find the relevant prefix for transform we would use:

Modernizr.prefixed('transform');

The value returned in this instance is a string that is relevant to your browser, as per the list above. Therefore, if we include Modernizr 2.5 in our code we can use:

$('#myElement').click(function() {
  var transform = 'scale(2)';
  this.style[Modernizr.prefixed('transform')] = transform;
});

As you can see, the saving is immediately apparent. Five lines of code for vendor prefixes has become one. When a particular browser stops uses the prefixing, Modernizr Prefixer will automatically pass the correct non-prefixed value.

Confused about the square brackets? In JavaScript, dot notation and square bracket notation are interchangeable - both are used to access properties of objects. In our example, we are accessing the style property object of our element, and in turn the transform property from our style. Dot notation is tidier to write and easier to read, but does not allow us to use variables to select properties. Using square brackets we can use the result of Modernizr.prefixed('transform') to select the property we want.

But There's More..

Modernizr Prefixed can accept multiple parameters, giving it extra uses.

Modernizr.prefixed(str, obj[, scope])

If you wanted to not only find out the prefixed value but also check whether your prefixed property existed on a particular object, you could use:

$('#myElement').click(function() {
  var transform = 'scale(2)';
  this.style[Modernizr.prefixed('transform', this.style, false)] = transform;
});

This code tells Modernizr to look for a transform property within this.style's properties. This example should always return a string containing the vendor prefixed name, but testing other available functionality may return objects or functions; so to be safe we can ensure it does by supplying false as the third property. For example, Modernizr.prefixed('requestAnimationFrame', window) would return a function (as requestAnimationFrame is a function, not a property).

Binding functions to other functions

By returning a function, we can simply other common uses of vendor prefixes. For example, Paul Irish's shim for requestAnimationFrame (an improved way of animating elements or a canvas on a page at a regular interval) previously looked like this:

window.requestAnimFrame = (function(){
  return window.requestAnimationFrame ||
  window.webkitRequestAnimationFrame ||
  window.mozRequestAnimationFrame ||
  window.oRequestAnimationFrame ||
  window.msRequestAnimationFrame ||
  function( callback ){
    window.setTimeout(callback, 1000 / 60);
  };
})();

But now can be written as follows:

window.requestAnimFrame = Modernizr.prefixed('requestAnimationFrame', window)
|| function( callback ){
  window.setTimeout(callback, 1000 / 60);
};

Modernizr Prefixed again handles all the vendor prefix nastiness for us - meaning we just have to worry about the timeout condition for browsers that do not support requestAnimationFrame at all.

Vendor Prefix Appendix

If you're confused about which vendor prefix is used on each browser (and their casing), the below table is available to help you:

Browser CSS prefix CSS prefix example JavaScript prefix JavaScript prefix example
Mozilla Firefox -moz- -moz-transform Moz for properties and moz for functions MozTransform
Microsoft Internet Explorer -ms- -ms-transform ms msTransform
Opera -o- -o-transform O for properties and o for functions OTransform
Google Chrome -webkit- -webkit-transform Webkit WebkitTransform or webkitTransform
Apple Safari -webkit- -webkit-transform Webkit WebkitTransform or webkitTransform

* I can't find this documented anywhere… but this seems to be the standard that is followed. If you can confirm/correct this, please let me know.

You can read more about Modernizr Prefixed in the official documentation.