Prefix or Posthack
Issue № 309

Prefix or Posthack

As CSS browser support increases, including impressive strides by the IE9 team, more and more authors are plunging into CSS3. As they do so, they’re facing vendor prefixes—the -*- properties like -moz-border-radius, -webkit-animation, and so on.

Article Continues Below

Perhaps inevitably, there’s been some grumbling about these prefixes. There have been calls to drop them, or to collapse all the vendor-specific prefixes into a single prefix like -beta-. The primary pushback is that nobody really wants to write the same thing four or five times in a row just to get, say, rounded corners on an element.

While such grousing is understandable, it is exactly the inverse of what should be happening. We ought to praise vendors for using prefixes, and indeed encourage them to continue. Beyond that, I hold that prefixes should become a central part of the CSS standardization process. I do this not for the love of repetition, but out of a desire to see CSS evolve consistently. I believe that prefixes can actually accelerate the advancement and refinement of CSS.

Look back in horror#section2

To understand why we have vendor prefixes at all, it’s instructive to look back at the box model, which almost killed CSS before the turn of the millennium. Inconsistent box model implementations created a crisis. To escape the danger, we had to build an entirely new behavior on top of a markup feature and invent a whole class of hacks.

For the young whippersnappers in the audience who missed all the fun, what happened was this: In the first round of browsers that supported CSS, Netscape implemented the box model found in the CSS specification. That meant that width and height referred to the width and height of the content area. But Internet Explorer implemented the intuitive box model, which meant that width and height declared the dimensions of the box’s outer border edge.

Whichever of the two you think better, the fact remained that there were two major browsers with large user bases that were completely incompatible with each other. It was the late 1990s, we were fighting like hell to leave behind the morass of “this site best viewed in…” badges, and here we had a situation where a layout that worked fine in one browser could completely fall apart in another.

Compounding the problem was that neither browser could change its behavior to mirror the other. Assume for a moment that the IE team decided to change their CSS support to reflect the specification. To do so would mean that tens, even hundreds of thousands of sites that worked in IE would break—would quite literally fall apart, visually speaking—in the “fixed” version. While the standards community would have applauded the move, the rest of the world would have written off the browser as unusable. And even if the Working Group decided to change the specification to match IE’s behavior, Netscape would then have faced exactly the same problem.

Thus DOCTYPE switching was created. The entire regime of “standards mode” and “quirks mode” was born of this problem. The solutions to other problems were rolled into DOCTYPE switching, but the box model triggered it. Think about it: because two vendors did things differently, browsers now have to maintain two different primary rendering models and choose which to use based on an SGML declaration that says nothing about rendering.

Furthermore, the first wave of CSS hacks were devised to address exactly the same problem. The classic example of the genre gives it away in the title: The Box Model Hack. In fact, the hack itself was based on flaws in syntactical parsing of voice-family values, but nobody ever called it “the voice-family hack.”

The funny part is that this wasn’t the only instance where a box model inconsistency led to trouble. Not long after DOCTYPE switching saved CSS, the Explorer team implemented some features of CSS positioning. One of the properties they implemented was clip. Having learned their lesson with the box model brouhaha, the engineers at Microsoft paid very close attention to the specification and did what it said.

Shortly after they shipped it publicly, the CSS Working Group massively changed the way clip worked. The syntax looked exactly the same, but yielded very different results.

Once more, the specification clashed with the behavior of a publicly available browser (or, if you prefer, vice versa). The eventual resolution was to revert to the earlier behavior and drop the new behavior entirely. That renders clip effectively useless on any element with unpredictable height and width—which is to say, any normal-flow, non-replaced element such as a div or a paragraph. Although other solutions were proposed, they never came to pass, and clip withered away.

Imagine a different outcome#section3

Suppose that instead of implementing clip, the IE team had implemented -ms-clip. In that case, a behavior change in a later specification wouldn’t have been so difficult to overcome. Because a vendor prefix marks a property as “in progress,” it’s much easier for a vendor to go back and change it. Thus the IE team could have changed the way -ms-clip worked in their next release, explaining to developers that they were updating their experimental implementation to match changes to the specification.

Even if they had decided that that was impossible to do, the damage of the “bad” implementation would have been quarantined in the prefixed version of the property. Other vendors could have implemented the new version of clip (using their own prefixes), unaffected by what the IE team had done. A single vendor could not pin the specification and other vendors in place by their actions.

This is the promise that prefixes provide: A way to mark properties as “in progress,” and so not necessarily guaranteed to always act the same in future releases; an out for vendors who need to make those changes; and a defense against bad or premature implementations that happen to ship first. They add sorely needed flexibility to the advancement of CSS.

Of course, we could just say: “When a browser is wrong according to the specification, then they have to change even if it breaks the layout of web sites.” With prefixes, that’s a lot easier to accomplish, thanks to the warning that prefixes embody. Without prefixes, it’s very difficult or even impossible. Microsoft never did change the way it handled width and height in legacy pages—instead, it used DOCTYPE switching to behave differently on new (theoretically more “standards compliant”) pages. It was a useful and necessary trick, but that kind of trick only works once.

Even now we suffer#section4

Lest you think that all this silliness is an artifact of history, here are two cases of inconsistency happening right now:

  • Mozilla and WebKit browsers render box-shadow blurring very differently, and neither fully conforms to the specification. As I write this paragraph, a lengthy and heated debate is raging on the www-style mailing list. At least one, and possibly both, implementations will have to change the way they handle shadow blurring to achieve interoperability. The same holds true for any Microsoft or Opera implementations.

  • Mozilla and WebKit browsers both support gradients, but they use radically different syntaxes to achieve the same basic result. Now imagine a world where the vendors had implemented gradients without the prefixes. You would have three choices:

    1. Pick which browser gets a gradient and which one doesn’t.
    2. Use CSS hacks or browser sniffing to serve up different styles to different browsers.
    3. Walk away from using gradients entirely.

    And there are three choices here only because the gradients use wildly different value syntaxes, thus opening the door to option number one. In a case where two implementations use the same value syntax but have very different effects—as was true with clip—then there are really only the last two options: hack and sniff to send totally different styles, or just walk away.

We’ve seen this movie played out many times over the history of CSS.  There’s no reason to want to see it again. It was bad enough the first dozen times.

Prefix or posthack#section5

But are prefixes really any better?  After all, it’s been said that vendor prefixes are the new CSS hacks. As Aaron Gustafson pointed out in a recent article, this:

-moz-border-radius: 10px 5px;
-webkit-border-top-left-radius: 10px;
-webkit-border-top-right-radius: 5px;
-webkit-border-bottom-right-radius: 10px;
-webkit-border-bottom-left-radius: 5px;
 border-radius: 10px 5px;

…is reminiscent of this:

padding: 10px;
width: 200px;
w\idth: 180px;
height: 200px;
heigh\t: 180px;

In terms of repetition and annoyance, yes, the two are very much alike. But they’re fundamentally different in this way: Prefixes give us control of our hacking destiny. In the past, we had to invent a bunch of parser exploits just to get inconsistent implementations to act the same once we found out they were inconsistent. It was a wholly reactive approach. Prefixes are a proactive approach.

Furthermore, prefixes are a temporary hack. As time goes on and implementations become consistent, browsers will drop the prefixes. From then on, authors will be able to write one line for border-radius instead of six-plus lines of CSS. Without them, we’re just waiting for the next botched implementation that forces us to support it through hacks for years upon years.

That’s why creating a unified prefix, such as -beta- or -w3c-, is at least half a step backwards. It would preserve vendors’ ability to mark properties as “in progress” and make changes as needed. Unfortunately, it would completely rob authors of the ability to excise, or even feed a different value to, one particular browser if it has a botched implementation. From an author’s point of view, a unified prefix is no better than a world without prefixes.

I sometimes feel the same way about pre-processor methods to handle prefixes, whether on the server side (using tools like Less) or client side (any number of JS frameworks). When using these tools, it’s possible to just write border-radius declarations and have the tool expand that into the requisite list of prefixed declarations. On the one hand, they’re a very useful way to reduce typing and keep the authoring neat and clean. On the other, they’re just like a unified-prefixed or unprefixed world: one bad browser implementation away from breaking pages.

The advantage is that if something goes haywire, any author can go back, disable the pre-processor, and write out the prefixes by hand. Alternatively, the pre-processor can be updated to handle the problem. Either way it’s a little more cognitive overhead for the author, but not too much.

The downside is more philosophical, but it’s no less important for that: By hiding the prefixed properties behind a processor, authors may forget that what they’re using is experimental and subject to change.  Cognitively, they may start to treat what they’re using as settled and stable when it may be nothing of the kind.

Make prefixes really matter#section6

I believe so firmly that vendor prefixes are a good thing that I’m prepared to take the next logical step: Vendor prefixes should be made more central to the standards process. They should be required of newly implemented properties and should be the mechanism by which interoperability is declared.

Here’s what I mean: Suppose someone invents a new property called text-curl. Immediately, three vendors implement it. Each of them should be required to add a vendor prefix to their implementation. Thus, we’d see things like this:

h1 {
 -webkit-text-curl: minor;
 -moz-text-curl: minor;
 -o-text-curl: minor;
 text-curl: minor;
 }

Over time, the vendors refine their implementations in response to bug reports and clarifications by the Working Group. Eventually, the Working Group decides that two of the three are fully interoperable. Those implementations then get to support the bare text-curl. The third does not.

At that point, authors might decide to simplify their styles like so:

h1 {
 -webkit-text-curl: minor;
 text-curl: minor;
 }

Instead of hacks proliferating over time, they’re peeling away. Eventually, we’ll only need a single text-curl line.

So what happens when a new implementation debuts? It uses the prefix in its first release, no matter how many interoperable implementations already exist. That might mean that we’d have to go back and change the CSS to say:

h1 {
 -ms-text-curl: minor;
 text-curl: minor;
 }

Then, as soon as the Working Group deems the implementation of -ms-text-curl interoperable, the prefix can be dropped in the next release of IE. At that point the CSS can be reduced to a single, unprefixed line. Again, the number of hacks dwindles over time.

Of course, each of those vendors will continue to support the prefixed properties, so even if we don’t prune the prefixed lines, each supporting browser will recognize the unprefixed property and use it (since it comes after the prefixed declaration). For any browser that implements a prefixed version that doesn’t manage to get to an unprefixed state, its own prefixed property will still work. Even if the CSS is never touched again, it will continue to function.

Having said that, return for a moment to the time when the Working Group said that two implementations were interoperable and could thus drop the prefixes. That serves two purposes. First, as I said before, it marks a property as having enough interoperability to allow progress in the standards process.

But the other thing it does—and this is arguably more important—is force the vendors and the Working Group to work together to devise the tests necessary to determine interoperability. Those tests can then guide those who follow, helping them to achieve interoperable status much faster. They could literally ship the prefixed implementation in one public beta and drop the prefix in the next.

This reverses the way things are done now. As it stands, the process is set up so that when any CSS module reaches the Candidate Recommendation stage, vendors can drop the prefixes from properties in that module. But that just opens us up to the possibility of another botched implementation and a future of hacks to work around the error.

As proposed here, a module would be permitted to reach Candidate Recommendation once all of its properties had at least two unprefixed implementations in the wild. Any implementations that came after would start prefixed and drop the prefix once they had proven, in the wild, that their prefixed implementation matched the existing unprefixed implementations. Instead of being a minor gamble, unprefixed properties would come as close to a guarantee as anything we’ve seen to date.

Conclusion#section7

If the history of web standards has shown us anything, it’s that hacks will be necessary. By front-loading the hacks using vendor prefixes and enshrining them in the standards process, we can actually fix some of the potential problems with the process and possibly accelerate CSS development.

So the next time you find yourself grumbling about declaring the same thing four times, once for each browser, remember that the pain is temporary. It’s a little like a vaccine—the shot hurts now, true, but it’s really not that bad in comparison to the disease it prevents. And in this case, you’re being vaccinated against a bad case of multi-year parser hacking and browser sniffing. We suffered through that long plague once already. Prefixes will, if used properly, ward off another outbreak for a long time to come.

58 Reader Comments

  1. I personally don’t mind the concept of browser prefixes. However when thinking objectively about them, the do feel basically like sophisticated hacks. It’s a shorter and cleaner way of browser sniffing (and it works better). But like I said, I don’t mind writing them.

    However, I do think that a unified prefix could be beneficial for everyone involved. First and foremost, it reduces file size, which means faster load times, which Matt Cutts has recently mentioned is becoming a factor. Secondly, while we all would love to be our clients’ web designers from now until the day the internet is turned off, it doesn’t always happen that way. I have a handful of clients who I have not heard from since I received final payment from them. In these instances, while I agree with you Eric that vendor prefix usage will dwindle overtime, this will only occur if we as the designer are still involved in the site. If we are no longer in the loop, the client is stuck with extra code that is only slowing down their load times.

  2. shez,

    Its not about browsers fixing themselves in a given time span. Its about users. Any time a new browser is released, users start using it–and they don’t stop using it.

    I would much prefer prefixes over exploiting parser differences.

  3. Insightful article! I liked your observations about the experimental nature of working with CSS3 in its early stages—that designers should expect various browsers’ implementations of CSS3 properties might change over time—as well as the careful ordering of rules, from vendor-specific to general.

    Here are my thoughts on how the current system could be modified for the benefit of CSS designers and developers:

    1) Allow the use of vendor-specific prefixes to target browsers at ANY stage of CSS implementation.

    Browser differences are invevitable and, from time to time, need to be accomodated. We already have conditional comments for IE; why aren’t we able to target other browsers when necessary? Adding a vendor-specific prefix to a rule and placing it AFTER a general (or conflicting) rule could accomplish this quickly and easily.

    line-height: 1.1em;
    -o-line-height: 1.2em;

    2) Create a -beta prefix (maybe just a hyphen by itself?) to target new properties, with the option to override via vendor-specific prefixes.

    This approach could offer the best of both worlds: simplicity, with an option for specificity. When differences between implementations of a new CSS3 property are negligible, designers could rely on a single rule:

    -beta-box-shadow: 0 3px 10px #aaa;

    Or even simpler:

    -box-shadow: 0 3px 10px #aaa;

    When implementations are not so compatible, vendor-specific prefixes could be invoked:

    background: -moz-linear-gradient(top, #223344, #6c7782) repeat-x;
    background: -webkit-gradient(linear, left top, left bottom, from(#223344), to(#6c7782)) repeat-x;

    An obvious question regarding a broader application of vendor-specific prefixes (allowing them to denote both experimental and standardized versions of a property) is: Could this cause a design to fail once the specs/implementations change? Your article seems to respond by suggesting that such changes are to be expected regardless. Moreover, I suspect that careful placement of a more general rule would distinguish one case from other, and render the first case harmless:

    a)
    -ms-text-curl: minor;
    text-curl: minor;

    b)
    text-curl: minor;
    -ms-text-curl: minor;

    On the other hand, perhaps notation should more accurately reflect intent? In that case, vendor-specific prefixes (e.g., -ms) would best be used to target browsers, a beta prefix to target experimental CSS properties, and a combination of the two to target browser-specific, experimental implementations:

    -ms-beta-text-curl: minor;

    Much ado over a minor text-curl, huh?

  4. One major flaw in all this is the assumption that once a new browser is available, everyone will flock to and download it. I believe the persistence of IE6 is a testament to what will likely happen. A less extreme example can be found by digging through your analytics. I know I still see plenty of early builds of Firefox that have spotty prefix support at best.

    So, what’s the problem you might ask? How long do we leave the prefixes in our code? You talk as if one day in the near future everything will be all green fields and summer time, skies the purest blue, and web developers all frolicking as if Pan himself. I think it’s more likely that these prefixes are a more permanent feature of our CSS and thus less of a temporary fix to a problem, the working group not working fast enough.

    Interestingly enough, I see Safari being updated in my analytics at a much faster pace then anything else and that’s because Apple throws Safari updates in with OS software updates. Oh, if another vendor in Washington State cold get away with the same thing without getting a bunch of geeks panties all in a bunch, what a world that would be. We might be closer to your green fields and summer time, blue skies and frolicking.

  5. One problem with the vendor prefixes occurs when you access prefixed properties through JavaScript.

    In every browser, a dash indicates that the next letter of the property name in JavaScript is a Capital Letter. So “border-radius” becomes “borderRadius” in JavaScript. The same is true for vendor prefixes. “-moz-transform” becomes “MozTransform”. That makes it pretty easy to create a name translation algorithm.

    …if it weren’t for IE. IE does this differently. I discuss this at “my blog”:http://blog.attrakt.se/2010/11/browser-prefixes-in-ie-are-different.html

  6. I agree prefixes are better than all other options when different browsers use the same property differently.

    However, they are better because they are the lesser evil, which doesn’t make them better in the true sense of the word.

    There should be homogenous syntax in all browsers. Vendors are to blame here: it’s not that much of a complication to talk with eachother and do things the same way. Declaring gradients with positions first and colours later and vice-versa isn’t something that is complicated to unify. It’s not like vendors have to change the whole rendering engine, just how they parse parameters p1=position, p2=colour. EASY. They just have to discuss and think about what the Open Web is all about, because I can tell you it’s not about petty rivalry. They aren’t suppose to be first to the finish line to “sell” the product first. No one will “buy” Mozilla because THEY have rounded corners nailed and others don’t yet. It’s a different market.

    As for “you can drop the prefix once all is good” part, that will never work. You can’t trust people to always have the latest version of a browser. Just think of the high percentage IE6 still owns after what, 10 years or so?

    However, this WAS a very good article. So thank you.

    Stick a fork in me, I’m done.

  7. I have very simple idea. If any browser implementing new property would parse prefixed version as well as the non-prefixed version from the very beginning, than we could just stop to use the prefixed properties *until* we see that anything brakes. If for example new property text-curl is proposed then we just use

    text-curl: minor;

    in our stylesheets and wait what happens. When browsers start to implement the behavior properly, than we do not have to do anything. If for example IE implements it with bugs, then as soon as we read about it in designers blogs we just use the prefix to correct it by saying

    text-curl: minor;
    -ie-text-curl: normal;

    Yes, I am suggesting to put the prefixed version *after* the normal one, so we can override the behaviour for buggy browser.

    Before you start to criticize the idea, think about it – in fact this is exactly what we are already doing by automatically use the four different prefixes for any new property introduced. By writing

    -ie-text-curl: minor;
    -moz-text-curl: minor;
    -webkit-text-curl: minor;
    -o-text-curl: minor;
    text-curl: minor;

    we just say “I hope that everyone is implementing the property correctly” and only if/after we find out a bug we are correcting the css. So why not use the same approach with much less hassle?

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career