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 / browser | CH28 | FF23 | O12 | IE10 | remarks... |
---|
left | all | all | all | all | - |
---|
lEft | methods | methods | methods | methods | 1 |
---|
maxWidth | prop | prop | prop | prop | 2 |
---|
max-width | any | methods | methods | any | |
---|
mAx-width | any | methods | methods | any | 3 |
---|
|
---|
webkitColumnRuleWidth | prop | none | none | none | |
---|
webKitColumnRuleWidth | none | none | none | none | |
---|
WebkitColumnRuleWidth | prop | none | none | none | 4 |
---|
WebKitColumnRuleWidth | none | none | none | none | |
---|
wEbkitColumnRuleWidth | none | none | none | none | |
---|
-webkit-column-rule-width | any | none | none | none | 5 |
---|
-webkit-Column-rule-width | methods | none | none | none | |
---|
-webkit-cOlumn-rule-width | methods | none | none | none | |
---|
-Webkit-column-rule-width | methods | none | none | none | |
---|
-webKit-column-rule-width | methods | none | none | none | |
---|
-WebKit-column-rule-width | methods | none | none | none | |
---|
-wEbkit-column-rule-width | methods | none | none | none | |
---|
webkit-column-rule-width | none | none | none | none | 6 |
---|
Webkit-column-rule-width | none | none | none | none | |
---|
webKit-column-rule-width | none | none | none | none | |
---|
WebKit-column-rule-width | none | none | none | none | |
---|
wEbkit-column-rule-width | none | none | none | none | |
---|
|
---|
appleColumnRuleWidth | none | none | none | none | 7 |
---|
-apple-column-rule-width | none | none | none | none | |
---|
khtmlColumnRuleWidth | none | none | none | none | |
---|
-khtml-column-rule-width | none | none | none | none | |
---|
|
---|
mozOutlineRadiusBottomleft | none | none | none | none | |
---|
MozOutlineRadiusBottomleft | none | prop | none | none | 8 |
---|
mOzOutlineRadiusBottomleft | none | none | none | none | |
---|
-moz-outline-radius-bottomleft | none | methods | none | none | |
---|
-moz-Outline-radius-bottomleft | none | methods | none | none | |
---|
-moz-oUtline-radius-bottomleft | none | methods | none | none | |
---|
-Moz-outline-radius-bottomleft | none | methods | none | none | |
---|
-mOz-outline-radius-bottomleft | none | methods | none | none | |
---|
Moz-outline-radius-bottomleft | none | none | none | none | |
---|
mOz-outline-radius-bottomleft | none | none | none | none | |
---|
|
---|
msScrollLimitXMax | none | none | none | prop | |
---|
MsScrollLimitXMax | none | none | none | none | |
---|
mSScrollLimitXMax | none | none | none | none | |
---|
MSScrollLimitXMax | none | none | none | none | |
---|
-ms-scroll-limit-x-max | none | none | none | any | |
---|
-ms-Scroll-limit-x-max | none | none | none | any | |
---|
-ms-sCroll-limit-x-max | none | none | none | any | |
---|
-mS-scroll-limit-x-max | none | none | none | any | |
---|
-Ms-scroll-limit-x-max | none | none | none | any | |
---|
-MS-scroll-limit-x-max | none | none | none | any | |
---|
ms-scroll-limit-x-max | none | none | none | none | |
---|
mS-scroll-limit-x-max | none | none | none | none | |
---|
Ms-scroll-limit-x-max | none | none | none | none | |
---|
MS-scroll-limit-x-max | none | none | none | none | |
---|
|
---|
OTransformOrigin | none | none | prop | none | 9 |
---|
oTransformOrigin | none | none | none | none | |
---|
-o-transform-origin | none | none | methods | none | |
---|
-o-Transform-origin | none | none | methods | none | |
---|
-o-tRansform-origin | none | none | methods | none | |
---|
-O-transform-origin | none | none | methods | none | |
---|
o-transform-origin | none | none | none | none | |
---|
O-transform-origin | none | none | none | none | |
---|
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 :)