Dynamic style setting and vendor prefixes

2013-09-01

I've recently did some thorough research on different ways of setting an element style directly. There's so many ways of doing that and we need to catch them all. Vendor prefixes only make this harder because we might need to sync these styles to other browsers, where the applied vendor prefix might not work at all. In this post I'll explain some of the ways that we accomplish this.

Before we begin, I'll be using two terms to address two different ways of writing css properties. One is "dashed", which means background-color. This is case insensitive but will always be lower case, unless specified otherwise. The other is "camelcased", which means "backgroundColor". This version is case sensitive. Assuming the dashed property is lower cased, you can easily translate between the two by replacing dashes by upper casing the first character after the dash. And from camelcased by lower casing each upper cased letter and prefixing it with a dash.

Vendor prefixes pose a small difficulty in this process, since firefox uses Moz (upper case M), opera uses O, IE uses ms, and chrome (and safari?) use webkit AND Webkit. So when applying the transformation above, special care has to be taken for the prefixes.

The most common way of setting a css style on an element through JS is by accessing element.style.foo. This requires camelcase because dashes are not valid as part of a JS "identifier". Another way, very similar, is doing it dynamically; element.style[foo]. The big difference here is that you could also use the dashed version, in some browsers. The third method involves the less known style methods; el.style.setProperty(prop, val, important) and el.style.removeProperty(name) (and el.style.getPropertyValue(name), but that's not important here).

For this test, I will set a given property in all different ways. Afterwards I will check the el.style.cssText property and see if it's updated. cssText should update when you change a property (in all targeted browsers).

Directly setting a property dynamically, will simply be called "prop". When setting the property through dot, the property name must be properly camelcased anyways. Using the methods is called just that, "methods". I found that support for either method is the same. So if a browser supported setting some property through setProperty, it would also support it through removeProperty.

Targeted browsers are: Chrome 28, Firefox 23, Opera 12.16, IE10.

I've tested all kinds of combinations on a couple of properties, listed case sensitive. The vendor prefixed properties are carefully picked such that they target at least one browser, and such that each browser is at least targeted once for vendor prefixes (and because the test was automated, these are properties that accept px values). Here are my findings.



































































prop / browserCH28FF23O12IE10remarks...
leftallallallall-
lEftmethodsmethodsmethodsmethods1
maxWidthpropproppropprop2
max-widthanymethodsmethodsany
mAx-widthanymethodsmethodsany3

webkitColumnRuleWidthpropnonenonenone
webKitColumnRuleWidthnonenonenonenone
WebkitColumnRuleWidthpropnonenonenone4
WebKitColumnRuleWidthnonenonenonenone
wEbkitColumnRuleWidthnonenonenonenone
-webkit-column-rule-widthanynonenonenone5
-webkit-Column-rule-widthmethodsnonenonenone
-webkit-cOlumn-rule-widthmethodsnonenonenone
-Webkit-column-rule-widthmethodsnonenonenone
-webKit-column-rule-widthmethodsnonenonenone
-WebKit-column-rule-widthmethodsnonenonenone
-wEbkit-column-rule-widthmethodsnonenonenone
webkit-column-rule-widthnonenonenonenone6
Webkit-column-rule-widthnonenonenonenone
webKit-column-rule-widthnonenonenonenone
WebKit-column-rule-widthnonenonenonenone
wEbkit-column-rule-widthnonenonenonenone

appleColumnRuleWidthnonenonenonenone7
-apple-column-rule-widthnonenonenonenone
khtmlColumnRuleWidthnonenonenonenone
-khtml-column-rule-widthnonenonenonenone

mozOutlineRadiusBottomleftnonenonenonenone
MozOutlineRadiusBottomleftnonepropnonenone8
mOzOutlineRadiusBottomleftnonenonenonenone
-moz-outline-radius-bottomleftnonemethodsnonenone
-moz-Outline-radius-bottomleftnonemethodsnonenone
-moz-oUtline-radius-bottomleftnonemethodsnonenone
-Moz-outline-radius-bottomleftnonemethodsnonenone
-mOz-outline-radius-bottomleftnonemethodsnonenone
Moz-outline-radius-bottomleftnonenonenonenone
mOz-outline-radius-bottomleftnonenonenonenone

msScrollLimitXMaxnonenonenoneprop
MsScrollLimitXMaxnonenonenonenone
mSScrollLimitXMaxnonenonenonenone
MSScrollLimitXMaxnonenonenonenone
-ms-scroll-limit-x-maxnonenonenoneany
-ms-Scroll-limit-x-maxnonenonenoneany
-ms-sCroll-limit-x-maxnonenonenoneany
-mS-scroll-limit-x-maxnonenonenoneany
-Ms-scroll-limit-x-maxnonenonenoneany
-MS-scroll-limit-x-maxnonenonenoneany
ms-scroll-limit-x-maxnonenonenonenone
mS-scroll-limit-x-maxnonenonenonenone
Ms-scroll-limit-x-maxnonenonenonenone
MS-scroll-limit-x-maxnonenonenonenone

OTransformOriginnonenonepropnone9
oTransformOriginnonenonenonenone
-o-transform-originnonenonemethodsnone
-o-Transform-originnonenonemethodsnone
-o-tRansform-originnonenonemethodsnone
-O-transform-originnonenonemethodsnone
o-transform-originnonenonenonenone
O-transform-originnonenonenonenone


1: IE actually made it clear it treated properties without a dash as camelcased (and as such; case sensitive). As soon as it contained a dash, it became case insensitive.
2: None of the browsers accept camelcase to their methods
3: In which-ever way a browser supports dashed, it does so case insensitive
4: Note that chrome supports both webkit and Webkit in camel cased. Super confusing and inconsistent, of course.
5: Interesting enough, it supports the lowercase webkit for properties and methods, but any other casing for webkit only through the methods. Including the "w" capitalized.
6: I've tested whether leaving out the dash-prefix also works, but none of the browsers accept it (which is a good thing!)
7: Supposedly, chrome supports khtml and apple prefix as well on some properties, but I couldn't find any.
8: Note that firefox only supports the capitalized "m" Moz prefix.
9: Opera also only support the capitalized "o" as prefix. They should have just gone with opera instead... I actually don't know if they're supporting blink prefix (if that exists, anyways).

Some things to take away from all of this...

- Browsers seem to interpret properties that do not contain a dash as the camelcased type (IE displays this explicitly by only supporting lEft on methods, but mAx-width on property as well).
- Camelcased properties are case sensitive. Only webkit supports two ways of their prefix.
- The camelcased vendor prefixes are not very consistent when looking at the first character. Firefox and Opera demand an upper case first character, IE demands it lower case, Chrome accepts both ways. Bleh.
- When using dynamic properties, use the camelcase for safe cross-browser support.
- When using the methods, use the dashed properties for safe cross-browser support.
- For dashed vendor prefixed properties, never leave out the leading dash.

To see which properties (including vendor prefixed versions) are supported by a browser, it seems sufficient to get the window.getComputedStyle(document.body) object and check out all the properties. You might be surprised to see what kind of crap Opera (12) supports there... That list does appear to be exhaustive for all tested browsers. So if you're looking to see which properties are still vendor prefixed, getComputedStyle is the way to go.

Hope it helps you :)