Writing cross-browser, future-proof CSS 3

Here’s a quick tutorial (actually, rant) that came out of an aside I mentioned when doing my talk for Future of Web Design two weeks ago.

It came about when I was using the IE9 preview to test some sites. I noticed that a site that boasts rounded corners didn’t appear to have them in IE9, even though IE9 allegedly has border-radius support.

“Silly IE9″, I thought.

Wrong. Silly developer.

The difference between a pro developer and a wannabe is that the pro developer makes sites that are cross-browser and, as far as possible, future-proof. By contrast, the wannabe assumes that everyone is the same as him and therefore if the site works on the browsers he uses, that’s enough.

Our wannabe developer’s code looked like this


-moz-border-radius: 6px;
-webkit-border-radius: 6px;

By using only vendor prefixes, the wannabe developer ensures that this nice part of the design will only work on those browsers.

A pro, however, cares about his client so doesn’t leave them with a site that will need changing later. A pro cares enough about his site’s users to give the design to their browser and let it do with it as it will.

How?

Simply by adding the non-prefixed cross-browser version of the property, he can add border-radius support for IE9 now, Opera now and any new browser that comes along in the future:


-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;

In the above example, border-radius is pretty mature, so IE and Opera jumped straight to using the standard prefix-less property, but other fancy CSS 3 properties are implemented only with vendor prefixes at the moment. Note I said “at the moment”; in two years’ time, a new browser may consider that feature stable enough to implement without a vendor prefix and, because you’re a pro rather than a wannabe, you want to ensure your code works in 2 years time as well as today.

For maximum compatibility, I advise adding all vendor prefixes (I do it in alphabetical order to help me remember) plus the non-prefixed version.

So here’s a version that future-proofs and cross-browserifies™ CSS3 transforms:


-moz-transform: scale(1.6);
-ms-transform: scale(1.6);
-o-transform: scale(1.6);
-webkit-transform: scale(1.6);
transform: scale(1.6);

If, for example, IE adds support for the prefixless version, or uses the -webkit- version, you have one line—27 bytes—of redundancy. So what? And now your code works everywhere that has support, today and tomorrow.

And that’s how it should be.

I feel very strongly that using JavaScript to remove all that extra CSS away is a bad idea. Apart from the absurdity of using “20kb minified js to avoid 5kb ‘untidy’ CSS” (as one person commented about eCSStender), it’s ducking responsibility. If you as a developer choose to use experimental, pre-standardised code on a production site, then you need to live with the consequence of that choice. There’s no getting around it: experimental, pre-standardised code is susceptible to change. If the specification changes, you’ll need to change your CSS (which is easier to do if it isn’t being hidden away by some library).

See -o- vendor prefixed CSS supported in Opera 10.50, also Vendor-prefixed CSS Property Overview which compares vendor prefixes across browsers.

Resources

(Added Nov 2011)

18 Responses to “ Writing cross-browser, future-proof CSS 3 ”

Comment by George Ornbo

The woes of early adoption.. Five rules for one.

I’ve used SASS to help limit the repetition of proprietary rules but it makes me feel sick to the bottom of my don’t repeat yourself stomach.

Progress eh?

Comment by Georg Paul

I also put the vendor-prefixes in a separate stylesheet. In my standards compliant css files I am using e.g. “border-radius: 10px” and in the vendor-prefixes.css I’m using the same selector and write -moz- and -webkit-.. I think that makes the code cleaner..

Comment by Rik

This is a difficult tradeoff. Using the unprefixed version prevent later changes to a spec. Of course, for border-radius, there’s no question today, Opera and IE handle the unprefixed version. But for a long time, the two only implementations were different. So which syntax should you use with an unprefixed version ? The Mozilla or WebKit syntax ?

Same for CSS transforms, it’s a rather new spec and it might change a lot. CSS gradients is already very different in Gecko and WebKit. So I’d rather forget the unprefixed version and ensure that every browser has a good enough fallback.

Comment by Bruce

@robin, @George Ornbo yes agreed. But people seem desperate to use the newest shiniest stuff.

@markedup you’d think so, wouldn’t you? But since I mentioned it in 10 seconds in 40 minute talk, I’ve had lots of people ask me for more information. And I see the wannabe-code everywhere I look.

@Georg Paul – good idea, if it works for you. I’m so scatterbrained, I keep all my code together. But there are many ways to achieve cross-browser-nirvana.

Comment by Bruce

@Rik good point, which I’m adding to my article. Thanks. (That’s the trouble with rants – you have to apply caveats and subtlety retrospectively)

Comment by Vadim Makeev

Bruce, transform and transition syntax will change, accoding to Alex and Hokon (W3C, you know) so it’s a bit dangerous to use this properties without prefixes.

Comment by Damien

For the sake of code readability, maybe we should write the non-prefixed cross-browser version of the property first (?)

Comment by Rhyaniwyn

which syntax should you use with an unprefixed versionRik

The one that’s in the CSS3 Working Group’s specification. If it’s not specified at all yet, the one you like better.

What? What other criteria might you have?

Right, the specification isn’t finished. Of course, it’s subject to change. But you work with what’s there at the time you write the code. It might not change, or it might not change significantly! But even if it does it’s the final authority on CSS3 at any given point in time.

a bit dangerous to use this properties without prefixesVadim Makeev

Um…How? Prefixed CSS3 properties are in development every bit as much as the specification is and as such are subject to changes in syntax, changes in implementation, and (presumably) eventual obsoletion.

I recall reading in an older CSS specification that properties starting with a – (dash) are reserved for vendor specific or in development properties. That’s…just what they’re for.

So if you’re dealing with a CSS3 property that’s under development it’s not “dangerous” to use the property without the prefix, it’s exactly what you and the browser are each supposed to do when it’s not under development anymore.

So what that it’s still under development now? In the real world, we know through experience that there’s no good reason not to future-proof this way.

Even if a border-radius disaster happened there’d still be no good reason unless paranoia is your driving motivation.

write the non-prefixed cross-browser version of the property firstDamien

I see a lot of people do this and it annoys me. I don’t think it makes sense. Because you want the final, production ready, standard-compliant, non-vendor effect. It should be last so that, when the browser implements it fully, that is the one that has effect, not the testing version. Assuming the testing version stays around for some reason.

Visually I’d prefer to do the opposite order, too. But it just doesn’t communicate my intent.

Comment by Danny

Yea I´ve been doing this for a while now too, I tend to add my css3 rules at the bottom of the selector with the vendor specs grouped in a comment so they´re easy to remove, if that day ever comes.

Comment by yuxelt

Is there any spec that defines cascading order for these vendor specific rules?
Will “-o-transform” overrides “transform” when transform rule supported? Or -o-transform will be deprecated when this happens?

I’m trying to find a spec which defines how this code will behave when “transform” starting to be supported:

#foo {
-o-transform: scale(2);
transform: scale(3);
}

Comment by Project9

[…] not using the full vendor-prefix stack (-moz-, -ms- , -o-, -webkit-, [no prefix]) resulting in code that is neither future-proof nor cross-browser […]