Posted by: felipe | February 2, 2012

A proposal to drop browser vendor prefixes

Which reaction do you get by looking at the following code?

#elem {
  -moz-box-shadow: 0 0 10px gray;
  -webkit-box-shadow: 0 0 10px gray;
  -o-box-shadow: 0 0 10px gray;
  -ms-box-shadow: 0 0 10px gray;
  box-shadow: 0 0 10px gray;
}

Whenever you see some extremely verbose CSS like the above, written with all vendor prefixes (plus the unprefixed version), all of which look exactly the same, it really brings some rage mixed feelings. On one hand, you feel glad to have found a web developer who went out of their way to use experimental CSS features in the “right” way. On the other hand, you feel sad that we are asking them to do this.

Much has been said  about how CSS prefixes do more harm than good, and a lot of people have wanted to get rid of them, but there hasn’t been any proposal that didn’t cause (worse) shortcomings, allowed vendor experimentation to continue without disrupting the web, or offered an easy transition path. I’ll present here a proposal that I believe fixes all the existing problems with prefixes, makes it really easy to transition from experimental to recommended, and actually improves various aspects of web development and browser support for features that are on an standardization path.

The feature is simple, and there’s a TL;DR at the end, but let’s design it step by step to make sure we’ve covered everything.

(Let me here preemptively say, in true Graydon style: disregard the syntax of the proposal, focus only on the idea. The ideal syntax can be discussed later)

Feature unlocking

The basic idea is that, in order to use non-standard CSS features, instead of using prefixes on every declaration of that property, you only use it once at the top of the file to indicate that you’re willing to unlock that feature as implemented by that engine. For instance, the example at the top would become:

@-vendor-unlock {
  box-shadow: gecko, webkit, trident, opera;
}
...
#elem {
  box-shadow: 0 0 10px gray;
}

That means that the actual property declarations do not need to use the prefix, but the browser engine will still only accept the declaration if it has been explicitly unlocked. With that, when the feature reaches the status in which a vendor would like to drop the prefix (that is, by convention, candidate recommendation), all it needs is to start accepting the declaration unconditionally (that is, independent of being unlocked), without breaking every website that was using it before (unless the syntax changes, but more on that later).

Here’s a list of the properties that this approach bring:

  • Feature experimentation is still not unintentionally exposed to the web
  • It’s easier for web developers to use, which should encourage usage and testing for more than one engine
  • It makes it explicit for web developers that they are dealing with an experimental feature (instead of the “engine-only” feeling of prefixes)
  • When it’s time to make the feature a standard, websites don’t have to break and the engines don’t have to support the legacy syntax for a painfully long period of time
  • It allows the creation of developer tools for web developers (and browser developers) to force support a feature and thus test their website with a different engine
  • Browser vendors can start shipping new features with this approach without breaking existing support, and it doesn’t require a multi-year transition
  • Users will benefit from quicker multi-browser support by websites
  • It makes it easier for new engines to enter the market

Versioning

One problem that already exists with vendor prefixes, but that is not solved with the above suggestion, is syntax or feature changes. The whole purpose of the prefixes is so that vendors can experiment with feature support without making the promise that it won’t ever change. In practice, though, once a feature has been widespread enough, most vendors are tied to that and the decision to change the syntax or not is heavily influenced by that. While we are designing the new approach, we can also fix that! With feature versioning, web developers can explicitly target a version of the implementation, like so:

@-vendor-unlock {
  box-shadow: gecko/v1, webkit/v2, trident/v2, opera/v1;
}

This gives us:

  • Different implementations of a feature can exist at the same time
  • When the engines are tending towards an unified version (say 1st version of a feature in gecko was different than 1st in webkit, but they match at version 2), it’s easier for developers to use it
  • When there’s a change in the syntax or behavior of a feature, the browser engine can choose to either gracefully support the previous version or not, on a case by case decision whenever it makes sense to do so. This is currently not possible since there’s no way to tell which version the webpage is expecting to use.

Syntax mismatches

The last problem is when two matching versions does not exist between browsers. That is, it’s not possible to write a single declaration that will work on different engines. In that case, there’s no way around having multiple property declarations, and an override must be provided. To do that, the vendor prefix plus the version is used, and the feature still has to be unlocked, which guarantees that there’s no reason to just use the “good old prefix” except for mismatching reasons. Also, the prefix should be used to the engine that is probably leaning in the wrong direction than what will be made the standard.

As an example, let’s imagine a property called foobar that webkit and gecko implements, with two size arguments (<left> and <right>), but each takes on a different order.

@-vendor-unlock {
  foobar: gecko/v1, webkit/v1;
}
#elem {
  foobar: 10px 5px;
  -webkit-foobar-v1: 5px 10px;
}

Now, let’s say that webkit decided to change the order to match gecko’s, and the other engines followed. Then the only change required is to add the other engines and another entry for the second version of webkit:

@-vendor-unlock {
  foobar: gecko/v1, webkit/v1, webkit/v2, opera/v1, trident/v1;
}
#elem {
  foobar: 10px 5px;
  -webkit-foobar-v1: 5px 10px;
}

With this change, the webpage supports the experimental versions of foobar, plus the standardized (unprefixed) version whenever it reaches candidate recommendation, plus the differing version 1 in webkit if it wants to.

TL;DR

Browser vendor prefixes are polluting the web so much while making web development harder, which is the exact opposite of the two main reasons it exists. The main idea to fix that is that the property declarations should be written unprefixed, while an explicit unlock and versioning is instead used to activate these features on browser engines. An example would be:

@-vendor-unlock {
  border-radius: gecko/v2, webkit/v1, opera/v1, trident/v1;
}
...
#elem {
  border-top-left-radius: 5px;
  border-top-right-radius: 10px;
}

Note that with this example I also implied that the unlocking mechanism can be used for whole features, not only direct property names, such that you could use “css-animations” to unlock all the animation-delay, animation-timing-function, @keyframes, etc.

P.S.: I’ll be at FOSDEM this weekend if anyone is interested in discussing this idea during the conference.


Responses

  1. Can we use browser prefixes on non experimental properties? This would make browser targeting very easy, especially if you could also target browser versions.

    -moz-v9-background-color:
    -ie-border:

    • I don’t think so. The idea is to reduce browser targeting, not increase it. Also note that the version number is a feature version, not app version. And with various browsers on fast release processes, targeting specific versions is not a great idea.

  2. Three things have come to mind so far as I’ve been thinking about this.

    1) How can these vendor unlocks be added/removed/updated from Javascript?
    2) How can these vendor unlocks be added/removed/updated from inline styles?
    3) Adding a vendor unlock after all of the styles have been applied to a page may require reparsing/reapplying all the styles to see if one should be applied now. Do you know of a way to remove this performance penalty? Or maybe it is edge-case enough that it is OK if a browser is slow in this situation?

    • I don’t know if dynamic unlocking should be supported, but if the answer is yes, then the feature could be used as scoped blocks instead, similar to media queries or @-moz-document. This should cover all the cases you mention, I believe.

  3. That looks pretty good overall. Way better than the current situation.

    The versioning issue has to be ironed out though. I think version should be required in the @-vendor-unlock rule. Because when the first iteration is introduced, we don’t know if a second iteration will be needed or not.

    • Rick: yeah, I agree that versioning should be required too, otherwise we’re still stuck with a bunch of the existing problems.
      I guess I didn’t made that clear in my post as I tried to iteratively present the idea.

  4. that would be a great thing for the web standards.

    No matter what marketing bs you’ll hear about web standards, stuff like prefixes are the very opposite of the meaning of “standard”

  5. Why doing this:
    @-vendor-unlock {
    box-shadow: gecko, webkit, trident, opera;
    }

    instead of this:
    @-vendor-unlock {
    box-shadow;
    }

    Seems like it would be better for the web to just say “I want to use that feature even if it’s experimental”. There are different behavior and syntax issues but that is something authors should have to deal with when using experimental features, shouldn’t they?

    • If you did that you may as well use:
      exp-box-shadow: blah;

      if vendors would agree on a common prefix there would be no problem.

      • I like this idea 🙂

        exp-box-shadow : 2px 2px #FFF;
        box-shadow : 2px 2px #FFF;

        It’s simple.

    • Like the overall concept explained in this post. Mounir’s suggestion could be optional with something like:

      @-vendor-unlock {
      box-shadow: all;
      }

      I expressed my concerns about vendor prefixes back in 2007: http://thelucid.com/2007/10/30/proprietary-css-rules-are-we-returning-to-1995/

  6. […] genutzt werden, was wenig übersichtlich ist und manches Problem bereitet, wie Gomes kritisiert. Er ist damit nicht […]

  7. Awesome.

    Though as long as we’re referring to enginers and not browsers, that should be “presto”, not “opera” 🙂

    What about vendor-prefixed tokens that aren’t properties, e.g. the gradient functions or flex-box display value? Treating them all as though they were property names could lead to some name collision—especially for names that are purely vendor inventions, like some of Gecko’s XUL extensions.

  8. What exactly is it that you are trying to solve? I think you’ve identified two problems:
    1) Having to write the same rule four times
    2) Having to explicitly list the engines you support (which makes it hard for new engines).

    Let’s also consider the reason browser prefixes were introduced in the first place: the global css namespace is a valuable commodity. Once an unprefixed property is supported by a browser it becomes very difficult to use that property in any other way.

    The whole argument reminds me of how we used to sniff the browser version in javascript, but best practise has now moved to use feature detection which works with any number of engines, even ones not released when you wrote your script.

    I think I have a solution to all of these problems, which is to use a prefix per feature, rather than browser. I’d set up a registry of experimental features, and when a browser vendor wanted to implement, say, a feature called “box-shadow” they would register that and be allocated -exp1-box-shadow. They would then be responsible for defining the spec for -exp1-box-shadow. Other browser vendors would come along, and if they thought it was a good spec they would implement a compatible spec using the same prefix. If they thought the spec could be improved, they would register -exp2-box-shadow.

    Eventually agreement would be reached, a spec published and we’d drop the prefix, as now.

    My intention is to take as much meaning out of the prefix as possible, so I am a little wary of using consecutive numbers. -exp2- wouldn’t necessarily be better than -exp1-, it would just be a syntax or feature spec that was started later.

  9. Something to consider when coming up with an idea like this is how will new users learn about it and how will sites teach it?

    One of the big problems when vendor prefixes were introduced was that people would write documentation for their own browser only. As a new user I might read an article on developer.mozilla.org about -moz-box-shadow. I change my page, test it in firefox and think everything it great, until I’m showing the site to my friend who happens to be a chrome user…

    We don’t want to (and can’t) force sites to explain the concept of prefixes every time the use them, so they need to be as obvious as possible.

    I think the danger with your proposal is that people will start recommending use of ‘unlock.css’ files. A bit like reset.css, these will simply unlock all the browser and features combinations that the author knows about, defeating the whole point of the new syntax.

  10. > there hasn’t been any proposal that didn’t cause (worse) shortcomings

    I’m curious: What worse shortcomings would be caused by the proposal I made in the post of mine that you linked to?

    > box-shadow: gecko, webkit, trident, opera;

    This is merely a syntactic transformation. It could address some authoring pain, but it fails to address the anti-competitive effects of having per-engine syntax and engine B not automatically getting to support content written for engine A when engine B implements the equivalent feature set later or when the page author in ignorant of engine B.

    > Versioning

    Instead of making the situation better than it is now, this proposal would make the situation more complicated. Have you asked if Gecko and Presto developers are OK with maintaining different versions of the same feature?

    It seems to me that versioning would make the anti-competitive aspect of vendor-specific syntax only worse, because a new entrant to the market would have even more to reverse engineer and to support.

    > Syntax mismatches

    The forward-compatible parsing rules of CSS make versioning unnecessary when it comes to grammar-incompatible syntax changes. Your example isn’t grammar-incompatible but semantically-incompatible. I think the best way to avoid having to have a technical mechanism for addressing this problem is to Just Say No to bikeshedding the syntax in ways that don’t already make it grammar-incompatible.

    • Thanks for the input, Henri. Here’s my reply:

      > I’m curious: What worse shortcomings would be caused by the proposal I made in the post of mine that you linked to?

      For worse shortcomings I was mostly thinking of the -x or -draft proposals, which you’ve pointed out in your blog that it is bad too. (it forces everyone to reverse engineer and implement the version that first implementer pushed to the web)

      > This is merely a syntactic transformation. It could address some authoring pain, but it fails to address the anti-competitive effect

      That’s right. I wasn’t clear enough that this is not valid in my proposal; that was just the first step. It shouldn’t be valid without versioning exactly because it doesn’t address the anti-competitive effect

      > Instead of making the situation better than it is now, this proposal would make the situation more complicated. Have you asked if Gecko and Presto developers are OK with maintaining different versions of the same feature?

      No, they don’t have to maintain different versions, it’s optional. Ideally they should only accept the latest version which also should match the standardized version.

      > The forward-compatible parsing rules of CSS make versioning unnecessary when it comes to grammar-incompatible syntax changes. Your example isn’t grammar-incompatible but semantically-incompatible. I think the best way to avoid having to have a technical mechanism for addressing this problem is to Just Say No to bikeshedding the syntax in ways that don’t already make it grammar-incompatible.

      Thanks, that’s good info, I didn’t know that versioning would be unnecessary with grammar-incompatible changes. This makes this even better by making the necessity of using the prefixed fallback even rarer.

      • I lost a paragraph in my previous reply:
        I like your proposal in theory (if I understand it correctly, you mean the “keep experimental features in experimental builds”), but I don’t think it has any chance of happening. Browser vendors are going at a fast pace and it will only get faster. The only proposal that has a chance of being accepted would be one that actually benefits them and the web at the same time.

  11. I agree with others here, we shouldn’t encourage browser vendors to create different implementation of a vendor-prefixed property.

    Someone shipped a property with a problematic syntax? Too bad, but don’t make it worse by adding versioning. This would only mean more quirks to document and complex syntax/APIs to feature-detect them in css & js.

    • Louis, previous versions don’t have to be supported. My idea is to make it easier to drop support for them. Since the webpage author explicitly says which feature version they are targeting, the browser vendor can easily move on to newer versions without having to deal with the name collision

  12. […] posted here: A proposal to drop browser vendor prefixes Click here to cancel reply. […]

  13. Think it’s fine as is. Specially now with Sublime Text 2 you can hit COMMAND+CONTROL+X and it does the syntax things for you. I mean, it’s either that or nada. I prefer that. I doubt they are going to change this. The Web is a moving target and evidently, yeah, the prefixes can get out of hand but it’s part of what comes with the Web being such a moving target.

    This is what we signed up for.

  14. […] Interesting idea by Felipe G on using a new at-rule, @-vendor-unlock , to tell the browser to use it’s experimental implementation of any particular property, rather than using a vendor prefix on that property. Unfortunately at this point, even if you could get all the browsers on board, you’d need to use this and vendor prefixes to get deep support, which makes the problem worse Direct Link […]

  15. I think this is a brilliant idea. Vendor unlocking would certainly alleviate the pain of writing the same rule four or more times. If I understand how browsers read stylesheets, each browser still reads the rule, but skips rules it can’t interpret (in Chrome’s dev window, it shows me that it couldn’t read -moz).Especially in cases like border-radius where the syntax is exactly the same, it’s ridiculous that I have to write four lines when every browser ignores 3 of them.

    This also gives us the distinct advantage of vendor-specific design. Chrome seems to offer more style options for the newer HTML5 elements, so I’d love to “lock” other browsers, but unlock Chrome. I can’t think of a better way to finally create styles for the meter element!

    an added benefit is creating “Unlock Resets”; modeling after Nicolas Gallagher and Jonathan Neal we “normalize” the syntactically similar properties at the start of our style sheets. A vendor-unlock reset would become just as popular as The Meyer reset pretty fast.

  16. I’d rather use the prefixes. That lets me know immediately, when I need to know (i.e. when updating the CSS), that I’m dealing with a potentially non-standard implementation. I don’t have to go check the top to see if that property is “unlocked.”

    Prefixes are also a fairly simple concept to wrap your head around. The only thing I might like to see is actually the ability to target major versions in the prefix (i.e. -webkit-16-rulename: or -moz-10-rulename: ) But I’m fine with it as is.

    If it is just the pain of writing the same or similar lines multiple times, look into SASS or LESS. There are also post-processors that will add in the prefixed CSS for you – you just write the rule.

  17. […] View article: A proposal to drop browser vendor prefixes […]

  18. If I am not mistaken, Firefox already implemented without vendor prefixes which I can use box-shadow, border-radius without “-moz” prefix.

  19. How do you propose we handle linear-gradient with webkit? There are two separate syntax we need to use; one following the W3C syntax and used by Safari/Chrome, the other with a more verbose syntax used by iOS.

  20. […] including using a single experimental prefix but applied per-browser using an @vendor rule, and FelipeGomeshasasimilarsuggestion, using the @vendor-unlock rule to activate experimental […]

  21. […] weitere Alternative auf Basis von Feature-Unlocking inklusive Versionierung findet sich hier. Auch ein sehr interessanter und cleverer […]

  22. This is the main reason why I have been working a lot on using lesscss (http://lesscss.org/). Declare all the above prefixes in a variable once and keep using the variable again and again as you want.

    I wish the features which lesscss has would have been default features for css.

  23. The problem is you are still specifying render engines.

    People would use:

    @-vendor-unlock {
    box-shadow: webkit;
    }

    For all the same reasons. I do love the idea though.

    So, do this instead:

    @-vendor-unlock {
    box-shadow, transition, transform
    }

    And you’re done. The problem with versioning? Who cares, right now there’s no control for it either. It simply breaks. And that’s FINE. Because we shouldn’t be relying on something THAT flimsy anyway. Let the developer shoot themselves, at least it’d break in all implementations!

  24. nice sharing good work really keep it on

  25. Matthew Wilcox:

    Agreed. In terms of versioning, if the syntax is different just have 2 rules for your gradients, with the more up-to-date version 2nd.

  26. […] Interesting idea by Felipe G on using a new at-rule, @-vendor-unlock, to tell the browser to use it's experimental implementation of any particular property, rather than using a vendor prefix on that property. Unfortunately at this point, even if you could get all the browsers on board, you'd need to use this and vendor prefixes to get deep support, which makes the problem worse. What we really need is for all browsers to implement auto-updating so eventually "supporting older …A proposal to drop browser vendor prefixes is a post from CSS-TricksOriginally posted from A proposal to drop browser vendor prefixes […]

  27. I’m afraid that we’ll just see that:

    @vendor-unlock {everything: webkit}

    and other vendors will be screwed same as before. It’s not only a problem of verbosity, it’s also a problem of developer ignorance:

    “WebKit is so cool and Firefox is just irrelevant and whining, so I’ll be writing WebKit-only pages”

    ^ daily occurrence on mobile web.

  28. I don’t like the idea of forced, automatic browser updates because I want to keep older versions available in my testing suite.

    And philosophically, I’m opposed to anyone acting on the arrogant and misguided assumption that he/she knows better than I do what I need/want.

    • Ding, Ding, ding ~ we have a winner… I will update my browser when I am ready to do so, period. Don’t interrupt my work flow because its convenient for you and not for me.

      Any excuse to force auto-update is always a mistake and very misguided. The user must be the final decision point WHEN TO UPDATE/UPGRADE. We ask the wrong question, Instead of asking whether we can or not, we need to ask whether we should.

      Just because you can do something, does not mean its intelligent to do so. There is no reason any production server/service should ever be down because of any automatic process, whatever it does. To allow that to happen is simply stupid.

      Your reason to have an older copy to test from is extremely valid…as anyone who caters to IE6 as of April 2012 can attest.

  29. […] Direct Link to Article — Permalink […]

  30. […] @-vendor-unlock is only slightly smarter, but in every possible way inferior to CSS Mixins. Would that the WG spent as much time on Mixins as they have on this prefix kerfuffle. […]

  31. […] Alternativen zum vendor-Prefix-Modell […]

  32. […] how do we move forward? What will happen? Some people have suggested prefixes like -beta and @-vendor-unlock but one major problem with that is that the experimental implementation or syntax across web […]

  33. […] A proposal to drop browser vendor prefixes […]

  34. […] A proposal to drop browser vendor prefixes […]

  35. […] to blame for the fracturing, methods to evangelize solutions and what to do moving forward. There are plenty of interesting and relevant posts out there as of recent with varied proposals and potential […]

  36. […] A Proposal to Drop Vendor Prefixes: Tired of bloated stylesheets from all the browser prefixes you need to add? I know I am. Felipe Gomes offers suggestions on how to drop the vendor prefixes. Good discussion in the comments. […]


Categories