Open BorisChiou opened 5 years ago
cc @emilio
cc @tabatkins
TL;DR is: why is it incorrect to serialize translate: 10px 0 0;
as translate: 10px
. I don't get which side effect the spec talks about, at least for translation and scaling I'm pretty sure there's no such side effect.
translateZ(0)
absolutely has side effects; it's a classic hack to trigger forcing the element onto its own rendering layer. Iirc all the 3d transforms do so, even if they're "identity" transforms otherwise.
As mentioned in https://github.com/w3c/fxtf-drafts/issues/313, that's WebKit/Blink-specific behavior. It's not clear to me that it's necessary to preserve that behavior with the individual transform properties.
I was under the apparently-mistaken impression that the effect was present in all browsers!
That said, it would still be quite bad if, in WK/Blink, the element flipped from 3d to 2d in the middle of an animation, triggering all the weirdness of being demoted and then promoted again. So long as this quirk exists, I lean towards making sure the underlying value is consistent with keeping such animations 3d the whole time.
I guess I'm wondering if we can make Blink not interpret translate: 10px 10px 0
as a 3D transform? (While leaving transform: translateZ(0)
as doing so.) I believe the individual transform properties are not shipping yet and are not implemented in WebKit so we can avoid propagating the quirk there?
Animating from translate: 10px 10px -10px
to translate: 10px 10px 10px
shouldn't trigger layer destruction/re-creation since so long as the element is animated, it effectively has will-change: translate
applied and hence should keep its layer throughout.
I'm not sure why we'd want to interpret 10px 10px 0
as a 2d transform. It's clearly 3d; the author supplied three values.
While you're right that a CSS animation will indeed preserve the layer, setting things manually (either in an animation, or statically in a group of things with different z values) will still cause it to change its rendering if a 0
z value is treated as 2d.
Why would it? I don't get it. The fact that the z axis is zero doesn't change anything, regardless of whehter the user provided it or not.
As I stated above, yes it does, at least in current Chrome/WebKit. 3d transforms render differently than equivalent 2d transforms.
That seems like a bug in Chrome / WebKit to me.
And with that I mean: That's not something that deserves a spec to be changed.
Bug or not (it at least partially is), it's been part of WK/Chrome's transform implementation since it first shipped, and the web depends on that behavior as a "promote to a layer" perf hack. (It also has implications on text anti-aliasing, iirc.) We don't simplify translate3d()
into a translate()
if it has a 0 z argument, or vice versa.
The distinction is even maintained in TypedOM, which distinguishes between an unpassed z
argument to CSSTranslate and a passed 0
value, and similar for the other 2d-and-3d constructors: https://drafts.css-houdini.org/css-typed-om/#dom-csstranslate-csstranslate
So far, I've carefully kept the various transform things consistent in this quirk, and I'd like to maintain that. I don't think we should drop it from some syntax forms and not others, because that makes it confusing to predict which behavior you're going to get in WK/Chrome browsers.
If we want to remove it, I'd like to remove it from all transform syntaxes.
You never simplify any transform function into another, unless you're interpolating, sure, but I don't think it compares apples-to-apples. I still think this is a bug. Browsers are much better at layerizing nowadays, and websites can use will-change: transform
if they need to hint the browser. So I think there's no reason to do this.
@chrishtr What do you think about this? Any chance of us being able to stop doing the "transform: translateZ(0);
causes rendering differences" behavior, since it's theoretically a no-op transform?
@chrishtr What do you think about this? Any chance of us being able to stop doing the "
transform: translateZ(0);
causes rendering differences" behavior, since it's theoretically a no-op transform?
I would like to make this change. The only reason we didn't already do it is out of concern for performance compatibility, and we already shipped the change for some low-memory devices.
I'll follow up with @progers to see if we can include this in current work.
Any chance of us being able to stop doing the "
transform: translateZ(0);
causes rendering differences" behavior, since it's theoretically a no-op transform?
This issue is about the translate
, rotate
, scale
properties, not the transform
property's functions. The suggestion is not that Blink change the transform
property "non-binding hint" behavior; simply that translate
etc. need not carry that behavior forwards as there is no web-compat need; authors can use will-change
(or a paused animation) as a standards-based approach.
That said, it would still be quite bad if, in WK/Blink, the element flipped from 3d to 2d in the middle of an animation, triggering all the weirdness of being demoted and then promoted again
That doesn't happen, at least in Blink. We detect that the property is animating.
More Blink implementation detail:
If an individual transform property has a non-zero 3D component (or transform
has a 3D function), Blink records a compositing reason: having a current 3D transform.
If an individual transform property (or transform
) is animating, Blink records a compositing reason: having a current transform animation.
If an individual transform property (or transform
) is mentioned in will-change
, Blink records a compositing reason: having a will-change transform hint.
Any of these compositing reasons, and others, are sufficient to cause 3D behavior.
There are exploratory Blink CLs to record in the computed style if the individual transform has a supplied 3D component. These complicate animation implementation for no benefit other than
carrying forward to individual transform properties the translateZ(0)
hint that predates will-change
.
This issue is about the
translate
,rotate
,scale
properties, not thetransform
property's functions. The suggestion is not that Blink change thetransform
property "non-binding hint" behavior; simply thattranslate
etc. need not carry that behavior forwards as there is no web-compat need; authors can usewill-change
(or a paused animation) as a standards-based approach.
That's true, but it seems to me it would be simpler to implement and more consistent for developers to just get rid of the current translateZ(0) hints. I think we will probably be able to do so now that GPU raster is pervasive, and there is an easy fix for a site which regresses performance.
All 4 browser engines serialize the gCS result for transform: scale3d(3, 2, 1)
as matrix(3, 0, 0, 2, 0, 0)
, i.e. they don't report a matrix3d
result.
This issue is about the translate, rotate, scale properties, not the transform property's functions. The suggestion is not that Blink change the transform property "non-binding hint" behavior; simply that translate etc. need not carry that behavior forwards as there is no web-compat need; authors can use will-change (or a paused animation) as a standards-based approach.
Right, I understand. But I don't like behavior being inconsistent when consistency isn't too bad, even if it's with a legacy bug.
That said...
I would like to make this change. The only reason we didn't already do it is out of concern for performance compatibility, and we already shipped the change for some low-memory devices.
and
All 4 browser engines serialize the gCS result for transform: scale3d(3, 2, 1) as matrix(3, 0, 0, 2, 0, 0), i.e. they don't report a matrix3d result.
both argue that the quirk should be removeable, which is great! If that's the case, happy to change all the supporting specs to match, and only consider something 3d if it's actually outside the screen's plane.
That doesn't happen, at least in Blink. We detect that the property is animating.
I assume your detection doesn't cover JS animations. So all JS animations would need to use will-change
. But will-change
doesn't really have defined behavior when it comes to which optimizations it uses for transformations. There's no way to say "will change to 3D" as opposed to "will change in scale" or "will change in position".
Even for CSS animations, it goes against general CSS behavior if pausing/freezing an animation at a translate Z of 0px has a different rendering compared to setting that transformation directly.
Worth mentioning as well, that for SVG there are some spec'd differences in behavior/validity for 2D vs 3D transformations (although implementations aren't all on board, e.g. for z-index).
There's no way to say "will change to 3D" as opposed to "will change in scale" or "will change in position".
Right, so all such changes must be applied with will-change:transform
. No problems there.
Even for CSS animations, it goes against general CSS behavior if pausing/freezing an animation at a translate Z of 0px has a different rendering compared to setting that transformation directly.
Yes, this is one of the issues I was concerned about. But it looks like Chrome is okay with changing this to not have behavior differences.
Even for CSS animations, it goes against general CSS behavior if pausing/freezing an animation at a translate Z of 0px has a different rendering compared to setting that transformation directly.
Yes, this is one of the issues I was concerned about. But it looks like Chrome is okay with changing this to not have behavior differences.
No change in Blink animation behavior was mentioned. Pausing/freezing a 2D CSS animation in Blink can still have a different rendering compared to setting that 2D transformation directly. Pausing a animation at transform: translate(10px, 20px)
is equivalent to having will-change: transform
.
I understood @chrishtr to only be discussing a Blink change to make non-animated transform: translate3d(10px, 20px, 0px)
be equivalent to transform: translate(10px, 20px)
.
If it's a render time clamp gCS will be 0
RESOLVED: 0 is allowed with 1px being the render time clamp
With the perspective
property, I understand the resolution to mean that 0px
gives gCS result 0px
but renders as if 1px
was supplied.
With the perspective()
function, I am less clear about the intent.
Does perspective(0)
give gCS result "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -Infinity, 0, 0, 0, 1)"
or "matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 1)"
?
[Edit - sorry, wrong issue. Intended for #413]
The CSS Working Group just discussed Is it necessary to serialize all 3 components of translate given the 3rd component is 0px
, and agreed to the following:
RESOLVED: For the individual transform properties if they spec a value that can be expressed as 2d we treat as 2d and serialize accordingly
RESOLVED: Require transform funcitons to be downgraded to 2d if possible
This has little dependency on the issue but it was mentioned several times in this discussion that chromium uses translate3d(0, 0, 0) and translateZ(0) as a compositing trigger. We are attempting to remove this in https://crbug.com/1012775.
@progers
Is there any conclusion on this issue? It seems that using --disable-features = DoNotCompositeTrivial3D
can no longer be disable.
This has little dependency on the issue but it was mentioned several times in this discussion that chromium uses translate3d(0, 0, 0) and translateZ(0) as a compositing trigger. We are attempting to remove this in https://crbug.com/1012775.
@yisibl, we attempted to remove the behavior where chromium uses trivial 3d transforms (e.g., transform: translateZ(0)
) as a compositing trigger but found the performance tradeoff to not be worth it (it led to a measurable increase in re-painting). Unfortunately, we had to return to using these as a compositing hint. If you are still having issues with chromium in this area, please file a bug at https://crbug.com and I will take a look.
In that case, Agenda+ to go back to tracking "author explicitly gave a 3d value, we should serialize it as such even if it's equivalent to a 2d value".
The CSS Working Group just discussed [css-transforms-2] Is it necessary to serialize all 3 components of translate given the 3rd component is 0px
, and agreed to the following:
RESOLVED: No change
I discovered (via git blame
) that while tests were added for this resolution, it still hasn't been edited into the spec. (If I hadn't happened to run git blame
, I would have left the conclusion in Chromium bug 1180311 and Chromium bug 1180387 that the tests were buggy.
I've made the changes for the first resolution in the spec in #6147.
I still need to work out exactly what the second resolution ("RESOLVED: Require transform funcitons to be downgraded to 2d if possible") means in terms of spec changes. It's not completely clear to me if the resolution was about just serialization, or about both serialization and interpolation, although I think it was the latter, and I think it also seems a bit odd if it were only the former, because it would mean that interpolation varies based on something that you can't see in the serialization. I think the implication of the discussion is that there should probably also be a note about the possibility of reverting the change if it's not sufficiently compatible.
I also need to figure out when "downgraded to 2d" happens. I'm thinking it makes sense for the specified value of the property to preserve the functions as they are, but the computed value to do any potential downgrading. So this change would apply to the model of what the computed value is (including both the "Computed value:" line and w3c/css-houdini-drafts#1052), and then how that value is used in interpolation.
Just a follow-up question of this issue. The new update of serialization of
translate
[1]:This question is only for the case:
translate: 100px 100px 0px
vstranslate: 100px 100px
. IIRC, it seems Gecko and Blink treat thetranslate(x, y)
astranslate(x, y, 0)
while converting it into a matrix for computation. (Maybe it will simplify it if it only has 2d components.) Basically, 3d transformation is different from 2d transformation (by using different number of axes), so my question here is, what is the potential side-effects if we serializetranslate: 100px 100px 0px
astranslate: 100px 100px
? If the side-effects is not obvious in this case, could we make it simpler?[1] https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization