Skip to content

[css-view-transitions-2] Figuring out whether a ViewTransition was skipped or not, is not possible #13379

Description

@bramus

The Need

There’s a bit of a gap in View Transitions, where it’s not possible for an author to, in the finished promise callback, know whether that promise resolved because the ViewTransition was skipped or whether the VT finished naturally.

Knowing this is necessary in cases where the author wants to do some cleanup (such as removing extra elements that were injected specifically for the View Transition). In my use-case specifically, I want to share data between the old and new VT, but that data needs to be removed when there is no more Active View Transition.

The Issue

Take the following code (live demo):

const startVT = async () => {
	
	// Skip the activeViewTransition if there was any
	// @NOTE: This step is not really needed, as the call to startViewTransition would auto-skip it
	if (document.activeViewTransition) {
		document.activeViewTransition.skipTransition();
	}
	
	const t = document.startViewTransition(() => {
		document.querySelector('output').innerText = performance.now();
	});

	await t.ready;
		
	// … do some stuff here that relies on the pseudos being available …

	t.ready
		.then(() => {
			console.log('READY RESOLVED')
		})
		.catch(() => {
			console.log('READY REJECTED')
		})
	;
	
	t.finished
		.then(() => {
			console.log('FINISHED RESOLVED')
		})
		.catch(() => {
			console.log('FINISHED REJECTED')
		})
	;
};

document.querySelector('button').addEventListener('click', startVT);

When successively clicking the button, you’ll simply get repeated logs of the following – there are no logs of REJECTED:

READY RESOLVED
FINISHED RESOLVED
READY RESOLVED
FINISHED RESOLVED
READY RESOLVED
FINISHED RESOLVED

Normally, when skipping a transition, the ready promise rejects … but only when it was not resolved yet, as detailed in step 7 of the “Skip the View Transition” algorithm:

  1. Reject transition’s ready promise with reason.

    NOTE: The ready promise may already be resolved at this point, if skipTransition() is called after we start animating. In that case, this step is a no-op.

Because the ready promise already resolved (the await t.ready;), step 7 is the no-op as mentioned in the note.

(You can also remove the await t.ready; and still have this behavior. It resolves really fast because it all happens in under a frame)

Furthermore the finished promise of the old VT also never rejects, because updateCallbackDone also resolved by that time. As per step 8 of the “Skip the View Transition” algorithm:

  1. Resolve transition’s finished promise with the result of reacting to transition’s update callback done promise

Trying to hack my way into a solution

I tried figuring out if a transition was skipped or not by doing the following check against document.activeViewTransition in the finished promise:

if (t == document.activeViewTransition) {
  // Transition was resolved Naturally
} else {
  // Transition was skipped
}

But that also won’t work because the activeViewTransition gets cleared before the finish callback gets executed, so this check is always false.

This is because the “Skip the View Transition” algo from css-view-transitions-2 first clears the active view transition before resolving finished:

  1. If document’s active view transition is transition, Clear view transition transition.
  2. Resolve transition’s finished promise with the result of reacting to transition’s update callback done promise

It is the last step of the “Clear view transition” algo that clears the active view transition:

  1. Set document’s active view transition to null.

Possible solutions

As it doesn’t seem solvable in userland code, I think this needs to be solved at the spec level. Turning to possible solutions, I can think of the following suggestions:

  1. Move “Set document’s active view transition to null” out of the “Clear the View Transition” algo and place it after step 8 of the “Skip the View Transition” algo. That way the finished promise can check against document.activeViewTransition.
  2. Pass some data into finished to indicate whether the transition was skipped or not.
  3. [insert your idea here]

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Thursday Morning

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions