csswg-drafts icon indicating copy to clipboard operation
csswg-drafts copied to clipboard

[css-view-transitions-1] Handling cases where transition constraints are broken mid transition

Open khushalsagar opened this issue 2 years ago • 1 comments

View transitions require a bunch of constraints to be satisfied by tagged elements listed here:

If any of the following is true:

usedTransitionTags [contains](https://infra.spec.whatwg.org/#list-contain) transitionTag.

element is not element’s [root](https://dom.spec.whatwg.org/#concept-tree-root) and element does not have [layout containment](https://drafts.csswg.org/css-contain-2/#layout-containment).

element is not element’s [root](https://dom.spec.whatwg.org/#concept-tree-root) and element allows [fragmentation](https://drafts.csswg.org/css-break-4/#fragmentation).

This state can also change mid transition. The simplest thing is to skip the transition in this case.

khushalsagar avatar Oct 13 '22 23:10 khushalsagar

Summary from offline discussion: It makes sense to abort the transition if per element constraints are broken, i.e., no layout containment or the element allows fragmentation. But detecting if the computed value of tags on all DOM elements has changed (so we now have duplicate tags etc.) adds more computation work. And that work would be to detect a developer bug and abort the transition. So not worth it.

Proposed Resolution: If constraints on elements participating in a transition become unsatisfied after a transition is running, the transition is aborted. Set of tagged elements participating in a transition is not re-computed after animations have started.

khushalsagar avatar Oct 18 '22 17:10 khushalsagar

One constraint (which I missed above) is that an element participating in a transition must generate a box (can't be display: none).

When walking through the DOM to identify named elements, we ignore DOM elements which don't generate a box (as if they had view-transition-name:none). See spec text here: "If transitionName is none, or element is not rendered, then continue."

A change in this state (such that the element no longer generates a box) should also skip the transition.

khushalsagar avatar Nov 15 '22 19:11 khushalsagar

Another option for an element changing to display: none (or being removed from the DOM):

If there's a ::view-transition-old: Remove the ::view-transition-new from that pair, and set the end position & size to the captured element's position & size. This means the animation would continue as if there was no captured element in the new state.

If there isn't a ::view-transition-old: Remove the ::view-transition-group.

If the element is reshown during the transition: Do nothing. It can't come back.

jakearchibald avatar Dec 01 '22 11:12 jakearchibald

@jakearchibald @khushalsagar Can you summarize what question you want to ask the WG? It's okay to have multiple options to consider (or even an open-ended question), but since there's been several threads of conversation I just want us collect in one comment everything we want the CSSWG to consider. :)

fantasai avatar Dec 06 '22 03:12 fantasai

In a transition group that has a 'new' component (as in, the end state of the transition is linked to a renderable element in the document), that element controls the final width/height/position of the ::view-transition-group and the natural size and image of the ::view-transition-new.

If that element changes layout or appearance, the ::view-transition-group and ::view-transition-new is updated.

But, what should happen if, mid-transition:

  • That element is no longer renderable (eg display: none or removed from the document)
  • That element becomes renderable again

And does the behaviour change depending on if the ::view-transition-group has a ::view-transition-old (as in, it's transitioning 'from' a captured element)?

The following options assume that the linking of source elements to ::view-transition-new via their view-transition-name is performed once. As in, changes to elements' view-transition-name do not impact the current transition.

It also assumes that "the element is no longer renderable" check is performed in the render steps, when the view transition currently updates its state per frame.


Option 1: Skip the transition

If the transition starts with a ::view-transition-new, then it's required that the source element is capturable until the end of the transition. Otherwise, the remainder of the transition is skipped.

Option 2: Adapt the transition, no backsies

If the element is no longer renderable:

If the group has a ::view-transition-old, then the group's associated ::view-transition-new is removed from the group. The size & transform of the ::view-transition-group becomes the same as its 'from' keyframe (meaning it stays in the same size and position as the old element).

This puts the ::view-transition-group into a state as if the ::view-transition-new wasn't there in the first place.

However, this would cause ::view-transition-old:only-child to match, and which could cause new animations to start mid-way through the transition.

If the group does not have a ::view-transition-old, then the ::view-transition-group is removed.

If the element becomes renderable again, no action is taken.

Option 3: Adapt the transition, with backsies

If the element is no longer renderable, the group's associated ::view-transition-new becomes 0x0, transparent.

If the group has a ::view-transition-old, the size & transform of the ::view-transition-group becomes the same as its 'from' keyframe (meaning it stays in the same size and position as the old element).

This is mostly as if ::view-transition-new wasn't there in the first place, but not quite.

If the group does not have a ::view-transition-old, the size & transform of the ::view-transition-group becomes 0x0, with no transform (placing the group in the top-left of the snapshot viewport).

If the element becomes renderable again, the state is updated again, allowing the element to reappear.


The two "adapt the transition" options seem to have weird trade-offs, so I think I'm happiest with option 1.

jakearchibald avatar Dec 06 '22 13:12 jakearchibald

Thanks for the summary @jakearchibald. +1 to option 1. Toggling of this state mid-transition seems like a bug rather than a pattern the developer would need for a particular UX.

khushalsagar avatar Jan 03 '23 20:01 khushalsagar

Reiterating the proposed resolution : "If constraints on new elements participating in a transition become unsatisfied mid-transition, the transition is aborted."

Note that this issue is limited to the behaviour if the constraints are changed by the developer during the transition. The exact constraints are already in the spec with active discussion on clarifying/relaxing them:

  • The element must have an associated box.
  • The element must have layout containment (#8139).
  • The element shouldn't allow fragmentation (needs more discussion).

khushalsagar avatar Jan 10 '23 18:01 khushalsagar

Since there is a clear resolution and agreement here in the issue, let’s try making this an async resolution.

The CSSWG will automatically accept this resolution one week from now if no objections are raised here. Anyone can add an emoji to this comment to express support. If you do not support this resolution, please add a new comment.

proposed resolution : If constraints on new elements participating in a transition become unsatisfied mid-transition, the transition is aborted.

astearns avatar Jan 24 '23 00:01 astearns

RESOLVED : If constraints on new elements participating in a transition become unsatisfied mid-transition, the transition is aborted.

astearns avatar Jan 31 '23 23:01 astearns