Cannot use prefix-specific overrides when using prefixfree #16

Open
KrofDrakula opened this Issue Oct 17, 2011 · 16 comments

Projects

None yet

6 participants

@KrofDrakula

This is really more of an issue of how to correctly handle vendor-specific rendering problems, but I'm logging this issue so you're aware of this effect.

When using different vendor-spefic selectors, I can easily specify CSS attributes for different rendering engines:

-webkit-transform: rotate(15deg) rotateX(0); /* Force Chrome to render as 3D, enabling antialias */
-moz-transform: rotate(15deg);
-ms-transform: rotate(15deg);
-o-transform: rotate(15deg);
transform: rotate(15deg);

Using prefixfree, however, writing something like this:

-webkit-transform: rotate(15deg) rotateX(0);
transform: rotate(15deg);

...turns the resulting CSS on Chrome into:

-webkit-transform: rotate(15deg) rotateX(0);
-webkit-transform: rotate(15deg);

This negates the vendor-specific attribute spec and reverts it back to a non-antialiased view.

Now, I know that this could be solved by simply applying a Modernizr-like class name for specific browsers (and platforms, like IE), but the alternative would be to assign vendor-specific attributes a higher priority than unprefix ones, eg. if the rule exists prefixed in addition to the unprefixed one in source, do not transform the unprefixed one. This enables the override which would fix this issue.

Again, not sure if this is something that should be handled by prefixfree or not, just putting it out there.

@LeaVerou
Owner

I've been thinking about this issue for a while, trying to come up with different solutions.

The one I had come up was to use comments like /* don't expand */ to not prefix anything in a declaration or /* expand */ to substitute a prefixed one with the current prefix.

I hadn't thought of the classes idea. That could be useful, although it would force you to use a separate rule, which I don't like, and it might encourage browser-specific CSS.

@KrofDrakula

Well the issue here is that this case is a version-specific fix, so I'm not sure if it's the domain of prefixfree to fix it.

One possible solution would be to not expand the universal attribute if there's a vendor-specific attribute available for the currently running browser (eg. webkit will not expand the above example, while others will).

@LeaVerou
Owner

Yes, that would be ideal. But it would introduce too much complexity in the algorithm that makes the substitutions so I'm trying to avoid it. I don't want to end up having to code a full CSS parser, that would be quite slow and would substantially increase the filesize.

@KrofDrakula

For sure. Just close the issue if you think it's outside the scope of the current (or future) implementation, I'm just putting it out there in case someone else stumbles onto this issue.

@LeaVerou
Owner

I'm not closing it, cause I really want to come up with a solution for it. Just not sure which one.

@LeaVerou
Owner

I added the classes functionality you suggested in this commit:

55fa4ce

but I'm still not closing it, as that doesn't solve all issues. For example, gradients will have different syntax once they become unprefixed and this won't solve that problem.

@paulwalker

Why not just reverse the order of the selectors? eg:

transform: rotate(15deg);
-webkit-transform: rotate(15deg) rotateX(0);
@LeaVerou
Owner

Yes, that's what I currently suggest people to do. But I don't like it much, as it's not future proof in most cases.

@yuchi
yuchi commented Oct 25, 2011

Actually using prefixed properties to bring specific css to specific browser, is actually the wrong path. If you want to apply a different transform on browsers which support transition (for example) then you should check for transition (Modernizr) and then change the transform.

@KrofDrakula

@yuchi: That doesn't solve the problem at all; Chrome 14 cannot be differentiated in this manner. The specific case here being that that browser is the only one needing the additional forced 3D transform, but its capabilities match a wide variety of different browsers.

I've been thinking more about this issue – maybe I should just stick with a single transform including 3D which would render this issue moot for all browsers. Granted, all browsers would then force 3D rendering, but at least it would be consistent.

@yuchi
yuchi commented Oct 25, 2011

Do you mean that -webkit-transform: rotate(15deg) rotateX(0); it's an hack over Chrome 14?

@KrofDrakula

It's a hack for Chrome 14 (jagged edges when rotating in 2D), but affects all webkits, yes. So far, I've been using this with positive outcomes, though it's a tradeoff between simplicity, convenience and targeting specificity.

If anyone has a better way of targeting (preferably not relying on browser sniffing), I'd love to hear it.

@oli
oli commented Jan 6, 2012

Specific for this example, but as the 3D transform doesn’t do anything and is only for WebKit, you could apply it to a nested element with a -webkit- prefix preventing -prefix-free from expanding it. Even an empty child span with a 3D transform will cause the parent text block to get the stronger anti-aliasing.

http://dabblet.com/gist/1569637

Update:
I found the bug: http://code.google.com/p/chromium/issues/detail?id=96769
Also, adding a background-color turns sub-pixel anti-aliasing back on in Chrome 16, but not in Canary
http://dropshado.ws/post/6142339613/resolving-anti-aliasing-on-webkit-hardware-accelerated

@KrofDrakula

Yikes. Just read the chromium issue thread. Thanks for those pointers!

@le717
le717 commented Jan 27, 2014

@LeaVerou I was lead here after discovering -prefix-free (which is a great library. I'm using it myself on my site. 👍) and learning of this limitation.

Perhaps I can provide a fresh take on fixing this bug. From read the conversation, it does not appear to be mentioned but it might have been privately considered already.

To heavily simplify here, -prefix-free currently:

  1. Gets the browser's vendor prefix
  2. Reads your stylesheet
  3. Checks if a property needs prefixing
  4. If so, appends the prefix.

The error being reported here is if a non-prefixed property is used after an already prefixed property. In this case, the second property is prefixed and the rule is invalid.

Again, this may sound simple or absurd, but I figured it was worth a shot to report.

The fix would look something like this:

  1. Gets the browser's vendor prefix
  2. Reads your stylesheet, storing all the properties in some form of array
  3. Checks if a property needs prefixing
  4. If so, check the array for an already prefixed version.
  5. If an already prefixed version is present (to reuse @KrofDrakula's example, -webkit-transform: rotate(15deg) rotateX(0);), do not prefix and move on to next property.
  6. Otherwise, append the prefix.

The only real drawback here is the array. If the stylesheet is massive, then the array will be massive as well, thus going through it and checking if a prefix is needed would slow the script down by a currently unknown amount. The if checking may also slow things down a bit, but I imagine not near as much as the array.

So yea, that's help. I don't know if this will help any, but I figure I would share this.

@LeaVerou
Owner

No, the drawback is that PF does not parse the stylesheet, so there is no array figured out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment