Dec 14

View Transitions API

Providing a native API for animated page and element transitions.

By Ryan Trimble

Using creative animations can provide enjoyable and memorable user experiences in many ways:

State changes, more specifically page transitions, are rather difficult to animate, however. There are several third-party JavaScript packages for managing page transitions, but there has not been a solid native solution to this as of yet.

The W3C CSS Working Group is currently working on a draft specification for a new native API for page transitions called View Transitions. 

Browser Compatibility

At the time of writing, the View Transitions API is unsupported in all major browsers as it is an extremely experimental feature within Chrome and is subject to change.

To enable this feature: you must be on Chrome (Canary) 109 or greater and enable the View Transitions feature flag at chrome://flags/#view-transition.

Basic example

A very basic example of View Transitions follows this pattern:

const viewTransition = () => {
if (!document.startViewTranstion) {
// handle unsupported browsers
}

document.startViewTransition(() => thingToTransition());
};

Inside the .startViewTransition() method, you can pass in any type of DOM manipulation you want. You aren’t limited to just page transitions here; you can also move elements from one parent element to another, add or remove elements, toggle classes, and more. 

Once the .startViewTransition() method is called, the View Transitions API creates snapshots of both the current state and the state that is being transitioned to, then performs the transition between the two. 

The default animation used in View Transitions is a crossfade animation, which looks something like this:

While the transition is occurring, a set of pseudo-elements is provided that we can use to customize the transition. 

Customizing Transitions

The pseudo-elements provided by the View Transitions API are organized into a tree, like so:

::view-transition
└─ ::view-transition-group(root)
    └─ ::view-transition-image-pair(root)
       ├─ ::view-transition-old(root)
       └─ ::view-transition-new(root)

These pseudo-elements can be used inside CSS to create more customized animations to occur during the transition. An important thing to note here is root refers to the default transition. Currently, this means everything being transitioned is the root transition. We can have multiple transitions by setting view transition names, where we can apply different animations to different transitions (more on that in a bit). 

A simple test customization is changing the animation duration via CSS, like so:

::view-transition-old(root),
::view-transition-new(root)
{
animation-duration: 5s;
}

This will slow down the crossfade animation to 5 seconds:

While the transition is slowed down, you can really see what is happening here: ::view-transition-old(root) is fading out the current state, while ::view-transition-new(root) is fading the new state in.

A smoother transition might be expanding the image to full size after clicking on a thumbnail. To do this, we need to set a few other CSS properties on the elements that are targeted during the transition.

There are actually multiple elements being transitioned here: the thumbnails on the gallery page and the full-sized image on the image page.

In our example, the thumbnail images are selected by targeting .gallery-item img. We will need to apply the contain: layout property to these thumbnail images like so:

.gallery-item img {
/* ...other styles */
contain: layout;
}

The contain property indicates that the element is as independent as possible from the rest of the page. The layout value isolates the element’s internal layout, preventing anything from the outside from affecting its internal layout. This is helpful as the layout of the element being transitioned needs to remain intact during the transition.

For the full-sized image, we will give it the contain: layout property as well, but we also want to apply a unique name to the view transition. We can do so by giving it the CSS property view-transition-name:

.full-size img {
view-transition-name: full-size;
contain: layout;
}

With just this CSS, we have actually accomplished the effect we are aiming for!

Applying a transition name will separate the transitions a bit, giving us a little more flexibility regarding how each transition can be animated. Now we can target both the root transition as well as the full-size transition when applying animations:

::view-transition-old(root),
::view-transition-new(root)
{
/* CSS animations styles for root */
}

::view-transition-old(full-size),
::view-transition-new(full-size)
{
/* CSS animations styles for full-size */
}

Completed transition:

Further Information

You will need Chrome Canary to test this with, but feel free to check out the source for the demo on Github

This is a super exciting feature, and I’m looking forward to when we can implement this on production sites. 

For more information on View Transitions, check out Jake Archibald’s article on the topic below, as it is currently the main reference for the API.

Other Resources:

Ryan Trimble

Ryan Trimble

User Experience and User Interface Developer for Ritter Insurance Marketing, living on a creek in central Pennsylvania. I like to write code and make people happy!

Ryan selected The Trevor Project for an honorary donation of $50 which has been matched by Netlify

The Trevor Project

The Trevor Project’s mission is to end suicide among LGBTQ young people.