Detect Vendor Prefix with JavaScript
Regardless of our position on vendor prefixes, we have to live with them and occasionally use them to make things work. These prefixes can be used in two formats: the CSS format (-moz-
, as in -moz-element
) and the JS format (navigator.mozApps
). The awesome X-Tag project has a clever bit of JavaScript magic that detects those prefixes in the browser environment -- let me show you how it works!
The JavaScript
The first step is retrieving the HTML element's CSSStyleDeclaration
:
var styles = window.getComputedStyle(document.documentElement, ''),
The next step is converting it to an Array
object and searching for a known prefix type, settling on Opera if none is found:
pre = (Array.prototype.slice .call(styles) .join('') .match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o']) )[1]
With the CSS prefix found, getting the JS-formatted prefix is simple:
return { dom: dom, lowercase: pre, css: '-' + pre + '-', js: pre[0].toUpperCase() + pre.substr(1) }
The returned object provides an object that looks something like:
Object {dom: "WebKit", lowercase: "webkit", css: "-webkit-", js: "Webkit"}
A complete representation of the vendor prefixing for the host browser. Here's the complete snippet:
var prefix = (function () { var styles = window.getComputedStyle(document.documentElement, ''), pre = (Array.prototype.slice .call(styles) .join('') .match(/-(moz|webkit|ms)-/) || (styles.OLink === '' && ['', 'o']) )[1], dom = ('WebKit|Moz|MS|O').match(new RegExp('(' + pre + ')', 'i'))[1]; return { dom: dom, lowercase: pre, css: '-' + pre + '-', js: pre[0].toUpperCase() + pre.substr(1) }; })();
Grabbing the CSSStyleDeclaration
from the HTML element is a clever move. This method plays off of the fact that there will always be a vendor-prefixed property in the style declaration, which some may dislike, but is going to be effective for a long time to come. What do you think of this method of vendor prefix detection? Share your thoughts!
Maybe I’m not getting this right, but as far as I’ve played with manipulating properties (that still need a prefix) via JavaScript, I was under the impression that:
– both
webkit
andWebkit
work for WebKit browsers;–
ms
works in IE, but notMs
;–
Moz
andO
work, but notmoz
oro
(Opera also recognizesWebkit
, but notwebkit
)link to test pen“>http://codepen.io/thebabydino/pen/HKstJ” rel=”nofollow”>link to test pen
Awesome find Anna! I’ll check that out!
Hi David,
Is there a way i can find is a css property value is supported by a particular browser. For ex: Android browser < 2.3 does not support overflow:auto or scroll. Is there a way i can find if the value is supported by a browser? i tried with javascript all i could find using document.body.style.propName but not for the property:value support.
Thanks
That’s particularly what should do
@support
in the future.You could dig into
Modernizr.testStyle
and check the element property. Like with:If the browser can’t support
scroll
, I guess it will stick onvisible
.I’m not sure, but i think you can create element, then apply desired value to property you want and check if it’s there :)
Like this:
Thanks everyone :)
@David Walsh: Well done!
@Deepak David: If you are looking for a generic approach look at Modernizr.
p.s.: I know it is not the problem of this solution, I just want to mention, that in older browser versions the css style name can differ from the official / non-prefixed style name, e.g.
-moz-border-radius-topright
vs.border-top-right-radius
. But this problem will fade away with time.It sure is an interesting way to detect style-prefixes.
But why not detect it depending on userAgent string? Webkit -> webkit, Opera -> O, Mozilla -> Moz and IE -> ms ?
And why store so many useful information u will never need like
{dom: "WebKit", lowercase: "webkit", css: "-webkit-", js: "Webkit"}
?I see the only reason to know a proper vendor prefix is for function that applies styles to the elements.
Something like this:
Sorry My English.
String indexing (e.g.
pre[0]
) is not supported by IE < 8. (As a side note, IE8 itself supports it for string literals only, not for string objects.)Also,
substr
is a non-standard String method. Why not just useslice
orsubstring
instead?IE8 and down isn’t supported by x-tag, so that isn’t in the realm of desire. As for substr, I’ll pass that on.
Internet Explorer supports prefix-less properties. So you should probably something more like this is appropriate in the modern world.
Hi David, thanks very much for sharing your efforts in making a JS function that tries to detect the vendor. I will try to use our code in the WP framework we’re working on. We generate CSS on client side (kind of like LESS does, but more simplistic) and I was looking for ways to minimize the CSS generated by our JS (in case you’re interested, see https://github.com/nexusthemes/nexusframework). In our framework the JS produces 779 CSS selectors. Injecting the CSS takes around 60 msecs on desktop (which is fair), but about 330 msecs on my ipad 1 in Chrome. I don’t know if lowering the amount of CSS will also lower the time it takes to process the CSs, but anything I can do to lower the 330 msecs sounds like worth investing :) Using your function I hope to reduce 6 lines of CSS;
Into just 1 or 2 lines.
Anyways, thanks again.
I’ve been using the snippet below in some of my jQuery plugins. How does it compare to your method?
Nice article.
How would one not use the the prefix, say, if the browser is able to run something prefix free?
For example, an up-to-date Chrome doesn’t need
-webkit-
for transform.thanks
Sorry, please delete that. Despite
cssText
apparently being supported by all browsers, Firefox returns an empty string :-(The ‘O’ should appear before ‘Moz’, else on opera it would match the lowercase ‘o’ in ‘Moz’.