Ordering CSS3 Properties

Avatar of Chris Coyier
Chris Coyier on (Updated on )

When writing CSS3 properties, the modern wisdom is to list the “real” property last and the vendor prefixes first:

.not-a-square {
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  border-radius: 10px;
}

Why is this method of ordering properties so commonly taught? Here is what it would look like “the wrong way”:

.not-a-square {
  border-radius: 10px;
  -moz-border-radius: 10px;
  -webkit-border-radius: 10px;
}

Even doing it “the wrong way”, won’t the border radius be the same no matter what, forever? A quick investigation might lead you to conclude that it will, and this ordering of properties is rather nonsense.

  1. The Long Long Ago: None of the properties are supported, order doesn’t matter.
  2. The Past: Only vendor prefixes are supported, order doesn’t matter.
  3. The Now: Both vendor prefixes and actual property are supported. If prefix is last, it will override actual property, but both are the same anyway.
  4. The Future: Only actual property is supported, order doesn’t matter.

Here’s a simple chart with this concept at work.

Woah there, Cowboy

The fact is, the ordering of CSS3 properties is important, and the above is fundamentally flawed. “The Now” is exactly the problem. We are at a crucial juncture in browser history where some browsers are supporting both the vendor prefixed version and the actual CSS3 property. Right now it’s specifically WebKit that is doing this, and the way they have implemented it is that if you list the vendor prefix after the actual property, the vendor prefix will override and be the property that renders.

Why does that matter? In the simple border-radius example we saw above, either way, the corners on that element will have a border-radius of 10px. There is no difference in how the vendor prefix and “real” property handle rounded corners when you set only one value. The problem is that there is a difference between the implementations of the properties when passing more than one value.

.not-a-square {
   /* These do totally different things */
   border-radius: 30px 10px; 
   -webkit-border-radius: 30px 10px;
}

The spec or “real” version will render the top left and bottom right corners at 30px and the top right and bottom left corners at 10px. The vendor prefix will render all four corners with elliptical corners 30px wide and 10px tall.

So if you’ve been blindly including the real border-radius at the end of your property lists using identical values, and then switch from Safari 4 to Safari 5, you’d see a dramatic change in how the above code was styling your boxes.

You could fix this up by fiddling with the values to make sure they do the same thing… but if you are going to fiddle with anything, you might as well fiddle with the real property as that will be supported version in the future. Listing the real property last is definitely the way to go. Because it will be based entirely on the spec, it will match other browsers implementations and will be the only supported version as time goes on and vendor prefixes are removed.

Border radius isn’t the only example here. Note the dramatically different syntaxes for background-image gradients. Now there is no “real” spec version of these values yet, but when there is, the implementation will be different than what we are using now. That should be listed last in the ordering of the properties to future proof that as well.

Thanks to @mattwiebe and @snookca for helping me understand this better.