Open noamr opened 1 month ago
A syntax alternative can be view-transition-style: motion || crossfade || composite || decoration || default
where default
means "motion when out of viewport, motion+crossfade when in-viewport"
Notes from internal conversation: for starts, having two modes is enough:
Perhaps view-transition-style: crossfade | morph
?
To discuss/resolve:
Copying from #9406 for the purpose of the CSSWG breakout.
There are 3 use-cases that can benefit from changing the way we capture in certain scenarios:
view-transition-group
: they need to capture opacity, filters, 3D, and sometimes borders, backgrounds & shadows in order to display in a way that doesn't look buggy.box-shadow
can have a nicer effect than flattening them into the snapshot.I see this as 3 styles of transition, with an auto
that generates default behavior:
crossfade
?)morph
?)transpose
?)auto
could mean:
morph
when the group contains other groupstranspose
when animating from very far from the viewport (100vw, 100vh?)crossfade
auto
could mean:* Use `morph` when the group contains other groups * Use `shapeshift` when animating from very far from the viewport (100vw, 100vh?) * Otherwise, use `crossfade`
Is there a reason for auto
not using morph
automatically if two elements with differing 3D transforms (or similar) are being transitioned between?
Because like this, transitioning one 3D transformed element to a differently 3D transformed element just crossfades between the two and it looks rather janky.
auto
could mean:* Use `morph` when the group contains other groups * Use `shapeshift` when animating from very far from the viewport (100vw, 100vh?) * Otherwise, use `crossfade`
Is there a reason for
auto
not usingmorph
automatically if two elements with differing 3D transforms (or similar) are being transitioned between? Because like this, transitioning one 3D transformed element to a differently 3D transformed element just crossfades between the two and it looks rather janky.
If an element is flat (doesn't have nested descendants), there shouldn't be a difference regarding the internal 3D transform (e.g. perspective
), as the image is flattened anyway. The external transform is part of transitioning the geometry in all the styles.
(Got my bikeshedding hat on …)
Perhaps
view-transition-style: crossfade | morph
?
The conversation here uses “capture mode“ as a term a lot, so maybe view-transition-capture-mode
seems better?
- Crossfade between the old and new element snapshots, like today (
crossfade
?)
crossfade
as a value feels weird here because authors can override the animation to something entirely different. IUC this is the current behavior where you get a flattened surface, so maybe flat
as a value is better here?
- Crossfade the contents and animate the box decorations individually (
morph
?)
layered
, maybe?
- Display the new content only and morph only the box decorations (
transpose
?)
This can already be controlled by authors, no?
::view-transition-old(x) { display: none; }
::view-transition-new(x) { animation-name: none; }
Most likely I’m missing something here … 🤔
All combined, I’m leaning to a view-transition-capture-mode: flat | layered | auto
syntax.
(Got my bikeshedding hat on …)
Perhaps
view-transition-style: crossfade | morph
?The conversation here uses “capture mode“ as a term a lot, so maybe
view-transition-capture-mode
seems better?
- Crossfade between the old and new element snapshots, like today (
crossfade
?)
crossfade
as a value feels weird here because authors can override the animation to something entirely different. IUC this is the current behavior where you get a flattened surface, so maybeflat
as a value is better here?
Yea, it's whether this property implies "what default transition would this generate" whether "what does it capture". I thought that referring to the default transition style is more design-oriented and referring to the capture is more technical, but perhaps more precise. This is definitely arguable!
- Display the new content only and morph only the box decorations (
transpose
?)This can already be controlled by authors, no?
::view-transition-old(x) { display: none; } ::view-transition-new(x) { animation-name: none; }
Yea, but doing this in advance is an optimization, see #9406. We can also decide to not fold this optimization in the solution for this issue.
Summary from internal sync, we concluded that we'd defer the no-content-change to later. There are 3 options on the table:
view-transition-style
or view-transition-capture-mode
), one option is like today, and the other one captures box-decorations & tree effects as style.auto
value. The capture-mode will be the same as today, unless the element is a containing group (has nested group descendants). This asserts that flat capturing doesn't make sense at all for a nested group tree, and it allows us to change that without breaking existing content.Note that there are current cases where cross-fading the whole image would be smoother than animating the backgrounds or clip-paths, see #10759 and #10760. However, this is also achievable by adding a container element, where the external container would have the view-transition-name
, and the internal container would have the backgrounds etc.
The CSS Working Group just discussed [css-view-transitions-2] Optionally capture some properties (e.g. opacity/border) as style instead of snapshot
, and agreed to the following:
RESOLVED: Change the capture mode for all view-transitions and specify how each property is affected by this capture mode change
RESOLVED: Blink will experiment and come back with changes needed if there are compat concerns
RESOLVED: eventually describe categorization of properties in the Module Interactions sections of each spec
The current way we capture view-transition participating elements is tuned to a flat tree of crossfade+transform animations: we save the element's relevant properties (transform from root, mix-blend-mode, color-scheme) and everything else is baked into the snapshot.
However, #10334 (nested transition groups) makes it so that this pattern might need to be expanded: to display clipping and tree effects in an expected manner, those would have to be copied into the group rather than baked into the snapshot.
The following (non-exhaustive?) list of CSS features would have a different behavior in a nested transition tree:
The "odd" one out of these is
border-radius
together withoverflow
: since it has a unique effect of clipping its descendant but not clipping the border.To render a rounded-corner element with nested clipped descendants correctly in terms of paint-order, the entire set of box decorations (backgrounds & borders) would have to be captured and applied to the group.
Also as per the resolution in #8282, we sometimes capture geometry only (when the old element is out of the viewport).
So at the very least there could be 4 capture modes (each one includes the ones above it):
geometry
flat
(geometry + snapshot + blend)composite
(clipping + 3D + tree effects)layered
(borders + background + shadow) (names bikesheddable to the bone)Superficially, it would seem like this can be done automatically:
geometry
when out of viewportflat
when in viewportcomposite
when has nested descendantslayered
when has nested descendants and clipping border-radiusHowever, the issue with these capture modes is that by default they're incompatible with each other - so if we used one capture mode in the old state and one in the new state, the animation and the captured image would be out of sync, creating a buggy-looking animation like this: https://codepen.io/noamr-the-selector/pen/OJeymbe.
One path forward is to enable the author to define the capture mode (based on the above proposal or some other subdivision we decide on), and encourage authors to use this when using nested transitions, but not choose a capture mode automatically (except for
geometry
when out of screen).