1. Introduction
This section is non-normative.
This specification introduces a DOM API and associated CSS features that allow developers to create animated visual transitions, called view transitions between different states of a document or an element, or between distinct same-origin documents.
1.1. Level 2 Updates
Level 2 defines the following, extending the model in [CSS-VIEW-TRANSITIONS-1]:
-
Cross-document view transitions, including the @view-transition rule and the algorithms that enable the cross-document view transition lifecycle.
-
Selective view transitions, a way to match styles based on the existence of an active view transition, and more specifically based on the active view transition being of a certain type.
-
Sharing styles between view transition pseudo-elements, a way to declare a style once, and use it for multiple view transition pseudo-elements. This includes the view-transition-class property, and additions to named pseudo-elements
-
Scoped view transitions, a way to perform view transitions within the scope of a DOM subtree.
1.2. Separating Visual Transitions from DOM Updates
Traditionally, creating a visual transition between two document states required a period where both states were present in the DOM at the same time. In fact, it usually involved creating a specific DOM structure that could represent both states. For example, if one element was “moving” between containers, that element often needed to exist outside of either container for the period of the transition, to avoid clipping from either container or their ancestor elements.
This extra in-between state often resulted in UX and accessibility issues, as the structure of the DOM was compromised for a purely-visual effect.
View Transitions avoid this troublesome in-between state by allowing the DOM to switch between states instantaneously, then performing a customizable visual transition between the two states in another layer, using a static visual capture of the old state, and a live capture of the new state. These captures are represented as a tree of pseudo-elements (detailed in § 3.2 View Transition Pseudo-elements), where the old visual state co-exists with the new state, allowing effects such as cross-fading while animating from the old to new size and position.
1.3. View Transition Customization
By default, element.
and startViewTransition()document.
create a view transition consisting of a cross-fade of the entire
root element between the two DOM states.startViewTransition()
Developers can instead choose which descendant elements are captured independently using the view-transition-name CSS property, allowing these to be animated independently of the rest of the page. Since the transitional state (where both old and new visual captures exist) is represented as pseudo-elements, developers can customize each transition using familiar features such as CSS Animations and Web Animations.
1.4. View Transition Lifecycle
A successful view transition goes through the following phases:
-
Developer calls
document.orstartViewTransition(updateCallback)element., which returns astartViewTransition(updateCallback)ViewTransition, viewTransition. -
Current state captured as the “old” state.
-
Rendering paused within the root element.
-
Developer’s
updateCallbackfunction, if provided, is called, which updates the document state. -
viewTransition.fulfills.updateCallbackDone -
Current state captured as the “new” state.
-
Transition pseudo-elements created. See § 3.2 View Transition Pseudo-elements for an overview of this structure.
-
Rendering unpaused, revealing the transition pseudo-elements.
-
viewTransition.fulfills.ready -
Pseudo-elements animate until finished.
-
Transition pseudo-elements removed.
-
viewTransition.fulfills.finished
1.5. Transitions as an enhancement
A key part of the View Transition API design
is that an animated transition is a visual enhancement
to an underlying document state change.
That means a failure to create a visual transition,
which can happen due to misconfiguration or device constraints,
will not prevent the developer’s ViewTransitionUpdateCallback being called,
even if it’s known in advance that the transition animations cannot happen.
For example, if the developer calls skipTransition() at the start of the view transition lifecycle,
the steps relating to the animated transition,
such as creating the view transition tree,
will not happen.
However, the ViewTransitionUpdateCallback will still be called.
It’s only the visual transition that’s skipped,
not the underlying state change.
Note: If the DOM change should also be skipped,
then that needs to be handled by another feature.
is an example of a feature developers could use to handle this.navigateEvent.signal
Although the View Transition API allows DOM changes to be asynchronous via the ViewTransitionUpdateCallback,
the API is not responsible for queuing or otherwise scheduling DOM changes
beyond any scheduling needed for the transition itself.
Some asynchronous DOM changes can happen concurrently (e.g if they’re happening within independent components),
whereas others need to queue, or abort an earlier change.
This is best left to a feature or framework that has a more holistic view of the application.
1.6. Rendering Model
View Transition works by replicating an element’s rendered state using UA generated pseudo-elements. Aspects of the element’s rendering which apply to the element itself or its descendants, for example visual effects like filter or opacity and clipping from overflow or clip-path, are applied when generating its image in Capture the image.
However, properties like mix-blend-mode which define how the element draws when it is embedded can’t be applied to its image. Such properties are applied to the element’s corresponding ::view-transition-group() pseudo-element, which is meant to generate a box equivalent to the element.
If the ::view-transition-group() has a corresponding element in the "new" states, the browser keeps the properties copied over to the ::view-transition-group() in sync with the DOM element in the "new" state. If the ::view-transition-group() has corresponding elements both in the "old" and "new" state, and the property being copied is interpolatable, the browser also sets up a default animation to animate the property smoothly.
1.7. Examples
function spaNavigate( data) { updateTheDOMSomehow( data); }
A view transition could be added like this:
function spaNavigate( data) { // Fallback for browsers that don't support this API: if ( ! document. startViewTransition) { updateTheDOMSomehow( data); return ; } // With a transition: document. startViewTransition(() => updateTheDOMSomehow( data)); }
This results in the default transition of a quick cross-fade:
The cross-fade is achieved using CSS animations on a tree of pseudo-elements, so customizations can be made using CSS. For example:
::view-transition-old( root), ::view-transition-new( root) { animation-duration : 5 s ; }
This results in a slower transition:
@keyframes fade-in{ from{ opacity : 0 ; } } @keyframes fade-out{ to{ opacity : 0 ; } } @keyframes slide-from-right{ from{ transform : translateX ( 30 px ); } } @keyframes slide-to-left{ to{ transform : translateX ( -30 px ); } } ::view-transition-old( root) { animation : 90 ms cubic-bezier ( 0.4 , 0 , 1 , 1 ) both fade-out, 300 ms cubic-bezier ( 0.4 , 0 , 0.2 , 1 ) both slide-to-left; } ::view-transition-new( root) { animation : 210 ms cubic-bezier ( 0 , 0 , 0.2 , 1 ) 90 ms both fade-in, 300 ms cubic-bezier ( 0.4 , 0 , 0.2 , 1 ) both slide-from-right; }
Here’s the result: