Nothing Special   »   [go: up one dir, main page]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-view-transitions-2] Nested transitions: what happens if there is a mismatch? #10631

Open
noamr opened this issue Jul 26, 2024 · 8 comments
Labels
Agenda+ css-view-transitions-2 View Transitions; New feature requests

Comments

@noamr
Copy link
Collaborator
noamr commented Jul 26, 2024

Follow up on #10334 (nested transitions)

It's clear what happens when both the old and new state have the same view-transition-group.
We need to specify, however what happens when there is a mismatch.
Note that this mismatch can happen by use of keywords like nearest.

Example:

A box sliding between two clipping containers
BoxToBox

Several solutions to a mismatch:

  1. new capture wins (like view-transition-class)
  2. Old capture wins
  3. Fallback to nearest common ancestor
  4. Split to two groups, one with the old pseudo and one with the new pseudo. The two groups have a default transform animation that represents moving the element from the old position to the new.

Trade-offs:

  • Option (1) is consistent with view-transition-class, however can create an abrupt experience: in the attached example, the element would disappear at the beginning of the transition and would animate in later.
  • Option (2) has the opposite issue: the element would disappear and would abruptly appear at the end.
  • Option (3) seems plausible and easy to understand, however would also have an abrupt effect, as all clipping would be lost for the duration of the transition and brought back at the end.
  • Option (4) doesn't have an abrupt effect by default, as the old element would animate out of the old position and the new element would animate into its new position, however loses the "crossfade" effect and might be a bit more complex to implement.

I tend to support option (4) because of the following:

  • Option (3), for example, is trivial to achieve by using the common ancestor as the containing group in the first place. So having it as the default for mismatch doesn't add much value.
  • Option (1) and (2) wouldn't work well (an even more abrupt effect) if the containing group has an entry/exit animation. The element would immediately disappear from the old container as the old container is fading away, and would fade in with the new element.
  • Crossfade might not be the right animation here anyway. When moving between different containers, those containers can have different backgrounds, and they might crossfade between themselves. So crossfading the internal element is not necessarily the correct default, though still achievable by selecting the appropriate view-transition-group.
@noamr noamr added the css-view-transitions-2 View Transitions; New feature requests label Jul 26, 2024
@noamr
Copy link
Collaborator Author
noamr commented Jul 26, 2024

@Psychpsyo
Copy link
Contributor
Psychpsyo commented Aug 3, 2024

I just ran into this while working on a site and I'd like to propose a modified version of option 3:
Creating a pseudo common ancestor that has a clipping shape that includes both containers and the space between them, somewhat like this:
image
This would avoid the moving child popping in or out on the opposite end of the containers.

One thing I'm not sure on is the exact shape of the ancestor since the clipping boundaries of the two containers might not be square. Ideally, the pseudo-ancestor would have its exact shape determined by some sort fill between the two containers that leaves their far edges as they are and only includes the space between that an element would be travelling through.
I think the most common problem would be rounded corners and maybe more fancy, nine-sliced corners/edges.

Also, here's my real-world example of this causing issues:

CrossUniverseClipping.webm

@noamr
Copy link
Collaborator Author
noamr commented Aug 6, 2024

One thing I'm not sure on is the exact shape of the ancestor since the clipping boundaries of the two containers might not be square. Ideally, the pseudo-ancestor would have its exact shape determined by some sort fill between the two containers that leaves their far edges as they are and only includes the space between that an element would be travelling through. I think the most common problem would be rounded corners and maybe more fancy, nine-sliced corners/edges.

Also, here's my real-world example of this causing issues:

CrossUniverseClipping.webm

Thanks for this! I am not sure how we can translate this into a solution though.
Note that clipping is just one example, there is also opacity blending and filters.
My current thinking is that "last capture wins" is the simplest and more consistent with existing stuff, especially since "nearest common ancestor" is trivial to achieve by using that ancestor in view-transition-group.

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 6, 2024
This tracks the view-transition-group for the captured elements
as "containing group". Those values are filtered to only include
ancestors.

* When a captured element has a valid containing group, the
  pseudo-element is reparented to the containing group when the
  view transition starts.

* Note that when capturing the old element, we don't deal with nesting
  at all. The tree for the purpose of allowing the compositor to
  capture the old state is flat. This can be revisited iteratively,
  it's done for implementation simplicity.

* When building styles, the (inverse) parent transform is adjusted
  so that it's not applied twice.

* Changed all the recursive functions to retrieve pseudo-elements
  to adapt to nested containers.

Currently, by default mismatches here are handled by
"last capture wins", however this is to be resolved in the CSSWG so it's not tested yet: w3c/csswg-drafts#10631

Note also that with the current implementation, after capturing the
old state and before starting might appear broken, as
clipping/opacity/etc are not applied to the generated pseudo-element.

Bug: 347947051
Change-Id: I49e4f7ea6c8d82b6ad34b50f8cda92eb3f074612
@nt1m
Copy link
Member
nt1m commented Aug 7, 2024

My current thinking is that "last capture wins" is the simplest and more consistent with existing stuff, especially since "nearest common ancestor" is trivial to achieve by using that ancestor in view-transition-group.

Agreed

aarongable pushed a commit to chromium/chromium that referenced this issue Aug 7, 2024
This tracks the view-transition-group for the captured elements
as "containing group". Those values are filtered to only include
ancestors.

* When a captured element has a valid containing group, the
  pseudo-element is reparented to the containing group when the
  view transition starts.

* Note that when capturing the old element, we don't deal with nesting
  at all. The tree for the purpose of allowing the compositor to
  capture the old state is flat. This can be revisited iteratively,
  it's done for implementation simplicity.

* When building styles, the (inverse) parent transform is adjusted
  so that it's not applied twice.

* Changed all the recursive functions to retrieve pseudo-elements
  to adapt to nested containers.

Currently, by default mismatches here are handled by
"last capture wins", however this is to be resolved in the CSSWG so it's not tested yet: w3c/csswg-drafts#10631

Note also that with the current implementation, after capturing the
old state and before starting might appear broken, as
clipping/opacity/etc are not applied to the generated pseudo-element.

Bug: 347947051
Change-Id: I49e4f7ea6c8d82b6ad34b50f8cda92eb3f074612
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5749090
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1338296}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 7, 2024
This tracks the view-transition-group for the captured elements
as "containing group". Those values are filtered to only include
ancestors.

* When a captured element has a valid containing group, the
  pseudo-element is reparented to the containing group when the
  view transition starts.

* Note that when capturing the old element, we don't deal with nesting
  at all. The tree for the purpose of allowing the compositor to
  capture the old state is flat. This can be revisited iteratively,
  it's done for implementation simplicity.

* When building styles, the (inverse) parent transform is adjusted
  so that it's not applied twice.

* Changed all the recursive functions to retrieve pseudo-elements
  to adapt to nested containers.

Currently, by default mismatches here are handled by
"last capture wins", however this is to be resolved in the CSSWG so it's not tested yet: w3c/csswg-drafts#10631

Note also that with the current implementation, after capturing the
old state and before starting might appear broken, as
clipping/opacity/etc are not applied to the generated pseudo-element.

Bug: 347947051
Change-Id: I49e4f7ea6c8d82b6ad34b50f8cda92eb3f074612
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5749090
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1338296}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 7, 2024
This tracks the view-transition-group for the captured elements
as "containing group". Those values are filtered to only include
ancestors.

* When a captured element has a valid containing group, the
  pseudo-element is reparented to the containing group when the
  view transition starts.

* Note that when capturing the old element, we don't deal with nesting
  at all. The tree for the purpose of allowing the compositor to
  capture the old state is flat. This can be revisited iteratively,
  it's done for implementation simplicity.

* When building styles, the (inverse) parent transform is adjusted
  so that it's not applied twice.

* Changed all the recursive functions to retrieve pseudo-elements
  to adapt to nested containers.

Currently, by default mismatches here are handled by
"last capture wins", however this is to be resolved in the CSSWG so it's not tested yet: w3c/csswg-drafts#10631

Note also that with the current implementation, after capturing the
old state and before starting might appear broken, as
clipping/opacity/etc are not applied to the generated pseudo-element.

Bug: 347947051
Change-Id: I49e4f7ea6c8d82b6ad34b50f8cda92eb3f074612
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5749090
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1338296}
@khushalsagar
Copy link
Member

My current thinking is that "last capture wins" is the simplest and more consistent with existing stuff

By "last capture wins" I think you mean we use the ancestor based on the new DOM? How do we deal with a case where the new element uses an ancestor which is not in the old element's ancestor chain? We have to figure out what the old transform should be in this case.

I'm not opposed to this idea but stuff like the above seems easier to reason about with "least common ancestor". Since you can always map the cached old transform to any ancestor. The fallback is more like the default flat mode.

@noamr
Copy link
Collaborator Author
noamr commented Aug 7, 2024

My current thinking is that "last capture wins" is the simplest and more consistent with existing stuff

By "last capture wins" I think you mean we use the ancestor based on the new DOM? How do we deal with a case where the new element uses an ancestor which is not in the old element's ancestor chain? We have to figure out what the old transform should be in this case.

The old element will save the final transform, and we'll project to be relative to the final parent.

I'm not opposed to this idea but stuff like the above seems easier to reason about with "least common ancestor". Since you can always map the cached old transform to any ancestor. The fallback is more like the default flat mode.

Is there more stuff like the above?

@khushalsagar
Copy link
Member

The old element will save the final transform, and we'll project to be relative to the final parent.

Ah, so figure out its transform relative to the root and map it into the chosen ancestor's space. Makes sense.

Is there more stuff like the above?

Everything else which is hierarchical (opacity, clip). If these effects are on the LCA then using that will look more correct. Though if they are on any node between the LCA and the new named element and we choose LCA then new would look wrong.

So I'm fine with both. As you said, if this doesn't work authors can always fix it by using the LCA as the parent explicitly.

@noamr
Copy link
Collaborator Author
noamr commented Aug 7, 2024

The old element will save the final transform, and we'll project to be relative to the final parent.

Ah, so figure out its transform relative to the root and map it into the chosen ancestor's space. Makes sense.

Is there more stuff like the above?

Everything else which is hierarchical (opacity, clip). If these effects are on the LCA then using that will look more correct. Though if they are on any node between the LCA and the new named element and we choose LCA then new would look wrong.

Opacity & clip are different from transform in that sense. They would be applied on the parent element, which would clip/mask the whole layer underneath. In some cases it would look different from the original state, but there is no way around it (except for putting view-transition-group: nearest on everything.

So I'm fine with both. As you said, if this doesn't work authors can always fix it by using the LCA as the parent explicitly.

Cool

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Aug 9, 2024
…r, a=testonly

Automatic update from web-platform-tests
Nested view transition: reparent & render

This tracks the view-transition-group for the captured elements
as "containing group". Those values are filtered to only include
ancestors.

* When a captured element has a valid containing group, the
  pseudo-element is reparented to the containing group when the
  view transition starts.

* Note that when capturing the old element, we don't deal with nesting
  at all. The tree for the purpose of allowing the compositor to
  capture the old state is flat. This can be revisited iteratively,
  it's done for implementation simplicity.

* When building styles, the (inverse) parent transform is adjusted
  so that it's not applied twice.

* Changed all the recursive functions to retrieve pseudo-elements
  to adapt to nested containers.

Currently, by default mismatches here are handled by
"last capture wins", however this is to be resolved in the CSSWG so it's not tested yet: w3c/csswg-drafts#10631

Note also that with the current implementation, after capturing the
old state and before starting might appear broken, as
clipping/opacity/etc are not applied to the generated pseudo-element.

Bug: 347947051
Change-Id: I49e4f7ea6c8d82b6ad34b50f8cda92eb3f074612
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5749090
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1338296}

--

wpt-commits: c0b10b3c6286687496b07265dfca91eb5923cc79
wpt-pr: 47494
i3roly pushed a commit to i3roly/firefox-dynasty that referenced this issue Aug 12, 2024
…r, a=testonly

Automatic update from web-platform-tests
Nested view transition: reparent & render

This tracks the view-transition-group for the captured elements
as "containing group". Those values are filtered to only include
ancestors.

* When a captured element has a valid containing group, the
  pseudo-element is reparented to the containing group when the
  view transition starts.

* Note that when capturing the old element, we don't deal with nesting
  at all. The tree for the purpose of allowing the compositor to
  capture the old state is flat. This can be revisited iteratively,
  it's done for implementation simplicity.

* When building styles, the (inverse) parent transform is adjusted
  so that it's not applied twice.

* Changed all the recursive functions to retrieve pseudo-elements
  to adapt to nested containers.

Currently, by default mismatches here are handled by
"last capture wins", however this is to be resolved in the CSSWG so it's not tested yet: w3c/csswg-drafts#10631

Note also that with the current implementation, after capturing the
old state and before starting might appear broken, as
clipping/opacity/etc are not applied to the generated pseudo-element.

Bug: 347947051
Change-Id: I49e4f7ea6c8d82b6ad34b50f8cda92eb3f074612
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5749090
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1338296}

--

wpt-commits: c0b10b3c6286687496b07265dfca91eb5923cc79
wpt-pr: 47494
ErichDonGubler pushed a commit to erichdongubler-mozilla/firefox that referenced this issue Aug 19, 2024
…r, a=testonly

Automatic update from web-platform-tests
Nested view transition: reparent & render

This tracks the view-transition-group for the captured elements
as "containing group". Those values are filtered to only include
ancestors.

* When a captured element has a valid containing group, the
  pseudo-element is reparented to the containing group when the
  view transition starts.

* Note that when capturing the old element, we don't deal with nesting
  at all. The tree for the purpose of allowing the compositor to
  capture the old state is flat. This can be revisited iteratively,
  it's done for implementation simplicity.

* When building styles, the (inverse) parent transform is adjusted
  so that it's not applied twice.

* Changed all the recursive functions to retrieve pseudo-elements
  to adapt to nested containers.

Currently, by default mismatches here are handled by
"last capture wins", however this is to be resolved in the CSSWG so it's not tested yet: w3c/csswg-drafts#10631

Note also that with the current implementation, after capturing the
old state and before starting might appear broken, as
clipping/opacity/etc are not applied to the generated pseudo-element.

Bug: 347947051
Change-Id: I49e4f7ea6c8d82b6ad34b50f8cda92eb3f074612
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5749090
Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org>
Reviewed-by: Chris Harrelson <chrishtr@chromium.org>
Reviewed-by: David Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1338296}

--

wpt-commits: c0b10b3c6286687496b07265dfca91eb5923cc79
wpt-pr: 47494
@noamr noamr added the Agenda+ label Aug 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Agenda+ css-view-transitions-2 View Transitions; New feature requests
Projects
None yet
Development

No branches or pull requests

4 participants