Sometime you need to apply some styles from within javascript code. Here is an example: you hove some elements with a transform property dynamically set, like:

<div class="rotating">...</div> <javascript> $('.rotating').css('transform', 'rotate(' + n + 'deg)') </javascript>

But it’s not that simple, old browsers has their own transform property:

-moz-transform

-webkit-transform

-o-transform

-ms-transform

No big deal, you think, lets set all of them:

<div class="rotating">...</div> <javascript> var transformValue = 'rotate(' + n + 'deg)' $('.rotating').css({ 'transform': transformValue , '-moz-transform': transformValue , '-webkit-transform': transformValue , '-o-transform': transformValue , '-ms-transform': transformValue }) </javascript>

But then you think “I want elements to rotate ‘smoothly’”. Year! there is a transition

$('.rotating').css({ 'transition': 'transform 400ms' })

And at this point our house of vendor specific cards breaks down. We have 5 possible names for transition property and 5 possible names for transform property. And we can’t even enumerate all of them:

var transitionValue = 'transform 400ms, -moz-transform 400ms, -webkit-transform 400ms, -o-transform 400ms, -ms-transform 400ms' $('.rotating').css({ 'transition': transitionValue , '-moz-transition': transitionValue , '-webkit-transition': transitionValue , '-o-transition': transitionValue , '-ms-transition': transitionValue })

The problem is that almost all browsers will reject given value for transition as ill-formed, because it contains unknown names of properties to transit.

What if we can actually know browser-specific property names? In such a setting above task is actually trivial:

var transformName = ... var transitionName = ... $('.rotating').css(transformName, 'rotate(' + n + 'deg)') $('.rotating').css(transitionName, transfromName + ' 400ms')

And that’s it! Actually it’s not that hard to find prefixed names for properties.

To detect what prefixed-variation of unprefixed-property is used by browser we can test all variations and return first supported

function getPrefixedName(unprefixed) { if (isSupported(unprefixed)) return unprefixed; var prefixes = ['-o-', '-ms-', '-webkit-', '-moz-'] for (var i = 0; i < prefixes.length; i++) { if (isSupported(prefixes[i] + unprefixed)) return unprefixed; } return undefined }

The key that can be used to check if property is supported is window.getComputedStyle function. This function returns an object that contains all possible CSS-properties and their styles for an element. It returns even implicitly set properties with their default values. We can use document.documentElement element as our scrutinee as this element should always be present in DOM-tree.

var documentStyle = window.getComputedStyle(document.documentElement)

Given the set of all supported properties we can check if property is supported

function isSupported(property) { return documentStyle[property] !== undefined }

But this won’t work! In the original code we used CSS-property names like border-radius , but in Javascript you should refer to property names with Javascript-friendly identifiers. border-radius becomes borderRadius . The conversion is not always consistent: sometimes first letter should be in upper case, sometimes in lower case, sometimes property name matches with javascript-keyword and custom prefix is added. We can ignore keyword-case as very rare. Considering all this we can implement isSupported as:

var isSupported = function (cssProperty) { var jsProperty = dashedToCamelCase(cssProperty) return documentStyle[jsProperty] !== undefined || documentStyle[firstLetterToLowerCase(jsProperty)] !== undefined }

Remaining helper functions are not hard to implement. Additionally we can detect all prefixed-properties only once and wrap them all in one object. Here is a full code for original example: