Lesson 34: View Transitions for SPAs
A common pattern for web pages is to use JavaScript to swap out the content on a page without loading a whole new HTML document. This is called a Single Page Application, or SPA. View transitions give you a way to show how the old page and the new page are connected.
Full page transitions
When your user moves to a new view in your SPA, your framework swaps out the DOM with new content. This makes the content just pop in. But what if you want to show a smooth change between the old content and the new content?
Transitions often show both the old and new views at the same time. For example, the old view fades out while the new view fades in. Because the old content is replaced, this was hard to do before view transitions.
To use view transitions, you wrap the code that changes the DOM in a callback.
For these examples, we have a basic router built by a web component called MyRouter.
How you turn on view transitions depends on the router and framework you are using.
document.startViewTransition(() => updateTheDOMSomehow());This turns on the default transition, which fades out the old view while fading in the new view.
What is happening here?
When you call document.startViewTransition(), the browser takes a snapshot of the old view.
It then runs the callback function that you pass, which updates the DOM to the new view but doesn’t show it yet.
When the callback function finishes, the browser starts the transition to the new content.
[!NOTE] Because view transitions are not yet Baseline Widely available, you should make sure that browsers without view transition support can still change to a new view, even if it isn’t animated.
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow();
return;
} else {
// With a View Transition:
document.startViewTransition(() => updateTheDOMSomehow());
}Customizing the transition
As you saw in the last example, the default view transition fades out the old view while fading in the new view. You can change the transition to better match your site’s style. You do this by styling pseudo elements that view transitions create for you.
You can set the leaving transition with ::view-transition-old() and the entering transition with ::view-transition-new().
You can also set values for both with ::view-transition-group().
In this example, the old view slides out using the slide-out-to-left transition.
The new view slides in using the slide-in-from-right transition.
They both last 200 milliseconds.
::view-transition-group(root){
animation-duration: 200ms;
}
::view-transition-old(root) {
animation-name: slide-out-to-left;
}
::view-transition-new(root) {
animation-name: slide-in-from-right;
}[!NOTE] Where does
rootcome from? For view transitions to work, you need an element in the old view and an element in the new view with the sameview-transition-name. By default, the browser sets theview-transition-nameof the document’s root element toroot.
Different transitions based on context
You may want different transitions based on what the user is doing. For example, clicking a link from your home page might slide the new view in from the right. Then you would expect that clicking a link to go back to your home page would slide the home view in from the left.
You can set different animations using the :active-view-transition-type() pseudo class.
html:active-view-transition-type(forwards) {
&::view-transition-old(root) {
animation-name: slide-out-to-left;
}
&::view-transition-new(root) {
animation-name: slide-in-from-right;
}
}You can then pick which view transition type to use when you call document.startViewTransition().
const direction = next === 'home' ? 'backwards' : 'forwards';
document.startViewTransition({
update: updateTheDOMSomehow,
types: [direction],
});Transitioning specific elements
So far you have only applied a transition to the root element to transition the whole view. But you can also use view transitions to animate specific parts of your pages.
For example, you may have content in the old view that matches content in the new view. This could be the title of the content or an image. It could even be a thumbnail image in the old view and a video in the new view.
First, you need to say which elements to transition, using the view-transition-name property.
For view transitions to work, each view-transition-name needs exactly one element before you call document.startViewTransition() and exactly one element after the callback in document.startViewTransition() finishes.
In this example, there is a music player that shows album art, the title, and the artist. An alternate view shows the same content rearranged, with song lyrics added.
In this example, there is exactly one of each transitioned element in the old and new view, and they even share the same selectors. The transitioned elements look like they move between their sizes and positions. The parts of the view that are not transitioned fade in and out.
Take a look at a more involved example. The home page on a blog may show a headline and image for each post, and these are also on the full page view of a blog post. When the user moves from the home page to a specific post, you may want it to look like the title and image move to their new spot to give context.
To do this for the title, you need a view-transition-name on the title element that is unique in the old view, shared with the title element in the new view, and unique in the new view.
This is tricky, because the home page has many headlines and images, and you don’t know which one the user will click.
You have two options to solve this.
You can add a unique view-transition-name for each post on the home page, and then match that name on each full page post.
You can build these using a post’s ID.
Your other option is to use a generic view-transition-name, but only apply it after the user clicks a post and before you call document.startViewTransition().
Designing transitions
View transitions are a set of tools you can use to guide your users and give them extra brand or context hints. You will likely use more than one technique to find the transitions that work for your site.
Depending on the effect you want, you may also need to tweak the elements or animations. In the previous example, several styles were adjusted to get the smooth transitions.
The headline has the rule width: fit-content.
This is a useful style when you transition text that doesn’t wrap, or that wraps the same way in both the old and new view.
Otherwise, the transition may be between elements with different widths, which makes the transition less smooth.
The image is also a different aspect ratio in the old view and the new view.
The example changes the animation and the object-fit property so the transition looks smooth.
Respecting prefers-reduced-motion
A common reason users ask for reduced motion is that full screen animations can cause discomfort for people with vestibular motion disorders.
View transitions can create these kinds of animations.
You can turn off animations using the prefers-reduced-motion media query.
You could also choose to provide gentler animations that still show how elements are connected.
@media (prefers-reduced-motion) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}Adapted from Learn CSS © Google and contributors, licensed under CC BY 4.0 (prose) and Apache 2.0 (code samples).