Dealing With Browser Differences in CSS 3

Cutting edge web technologies never come without a cost. Sometimes it means limited browser support for emerging standards, and other times it means having to go back and rewrite your code when draft standards change. When it comes to the still-in-progress CSS 3 spec, not only does browser support vary widely, but most browsers have […]
Image may contain Animal Mammal and Sheep
Woolly, the CSS sheep.

Cutting edge web technologies never come without a cost.

Sometimes it means limited browser support for emerging standards, and other times it means having to go back and rewrite your code when draft standards change.

When it comes to the still-in-progress CSS 3 spec, not only does browser support vary widely, but most browsers have implemented what are know as vendor-specific prefixes. The prefixes complicate things, and they require more work to drop them into your code, but they do serve a purpose.

For example, if you want rounded corners in CSS 3, you'd use border-radius to define them. But because border-radius is still being finalized, browsers only support their own versions of the rule. So, -moz-border-radius will target Firefox, -webkit-border-radius targets Safari and Chrome. For Opera, it's -o-border-radius.

None of the special prefixes will validate, which is less than ideal. There's a suggestion floating around that CSS validators should change their behavior regarding vendor prefixes by issuing a warning instead of an error. Regardless, if you want absolute standards conformance in your CSS code, you'll need to stay away from vendor prefixes.

However, if you want to play with CSS 3's new toys, you'll see there are some very good reasons why vendor-specific prefixes exist, and why you should use them (for now) in addition to the actual proposed rules of CSS 3.

To stick with the border-radius example, consider what happens when you want to target just one corner of an object. The spec was in flux in when the WebKit project decided to use -webkit-border-top-right-radius and Mozilla went with -moz-border-radius-topright. Without the prefix, you'd have to deal with two different CSS rules, potentially forever, with one of them eventually being depricated, but still out there in older versions of that browser.

Both prefixes are technically "wrong" and that's a good thing. Eventually, the final spec will be published and only one rule will be standardized, with all browsers implementing that rule. At that point, you can simply go into your code and delete all of your prefix rules. The vendor names make them easy to find and zap.

One thing you should definitely not do is target only one browser's prefixes. As Apple's disingenuous "HTML5" showcase recently highlighted, optimizing for a single browser is never a good idea.

If the idea of vendor-specific prefixes strewn about your otherwise standard CSS makes you uneasy, there is another possibility – offloading all the prefixing stuff to JavaScript.

Developer Arron Gustafson has written a critical article for A List Apart where he derides vendor-specific prefixes and offers a JavaScript alternative for those who feel the same way he does.

Gustafson refers to vendor prefixes as "forking" CSS. While we agree with his point, the word "forking" is problematic if only because there is nothing wrong with forking code. In fact, it's the norm in the open source world. (You are using Git or Mercurial right?). And vendor prefixes are not forks, they're hacks – temporary ways to push the boundaries of the web while standards bodies catch up.

Terminology aside, Gustafson's point is valid – ignoring standards and littering your CSS with browser-specific code are both bad ideas.

Gustafson's little JavaScript library can help you avoid vendor prefixes in your CSS. But, impressive as the script is, all it really does is offload the prefixing to JavaScript. The approach has some downsides – it means additional page load times and it neglects users who have JavaScript disabled.

If you want to start using CSS 3's features now, you're not going to avoid vendor prefixing, but at least you can choose how to handle it. Whether that means using the prefixes in your stylesheet, putting your vendor-specific code into separate stylesheets, or using a JavaScript solution like Gustafson's is up to you.

See Also: