View Transitions

View Transitions blog post cover image

Intro

Oftentimes I notice that I don’t pick the easy way of doing things. It was the case when I was develping the theme for this very blog. There are dozens of free Astro themes which I could apply in a minute and focus on content here…but no. It’s probably better to have my own theme. I’m new to Astro, so then I’ll have something which is my own creation plus I’ll get a collateral first hands-on grasp of the framework. Win-win. This is how the first post ended up to be about View Transitions.

View Transitions API

The View Transitions API is a powerful new web standard. It is available in Chrome, Edge and Opera from Summer 2024, Firefox and Safari are not supporting it yet. View transitions enable smooth animations between different states of a webpage. Whether you’re building a multi-page application (MPA) or a single-page application (SPA), this API provides a native way to create engaging transitions either between DOM states within a single page or across multipe pages. Just absorb how you don’t really perceive the page loads on this blog. Cool huh? (yes. I assumed you’re using a browser which supports the API.)

Historically within a single page you had to manually make sure that the old element visually disappears before the new one appears. This is CSS. Then you had to bring in the new element. This is JavaScript and CSS. Then you had to remove the old element. This is JavaScript (and CSS maybe). In the end of the day it required a lot of code and it was error prone. Trasnitions between pages were not even possible. This is where the View Transitions API comes to the rescue.

Native implementation

Want to see it in action? Check out the live native implementation demos for cross-document (MPA) transformation or in place (SPA) DOM transformations!

Basic setup for cross-document transitions

To implement view transitions without any framework, you need:

  1. A CSS rule to enable view transitions
  2. CSS pseudo-elements to customize the transition
  3. CSS keyframes to create custom animations for old and new states

Here’s a basic example based on the demo:

To enable cross-document view transitions, this at-rule is required:

/* Enable cross-document view transitions*/
@view-transition {
    navigation: auto;
}

To customize the transition, you can hook into the ::view-transition-group(root) pseudo-element:

/* Customize transition duration */
::view-transition-group(root) {
    animation-duration: 0.5s;
}

To create custom animations for old and new states, you can use the @keyframes at-rule:

/* Custom animations for old and new states */
@keyframes move-out {
    from {
        transform: translateY(0%);
        opacity: 1;
    }
    to {
        transform: translateY(-100%);
        opacity: 0;
    }
}

@keyframes move-in {
    from {
        transform: translateY(100%);
        opacity: 0;
    }
    to {
        transform: translateY(0%);
        opacity: 1;
    }
}

Then finally apply the animations to both the old and new states:

/* Old state animation applied to the element that is being removed */
::view-transition-old(root) {
    animation: 0.5s fade-out both move-out;
}

/* New state animation applied to the element that is being added */
::view-transition-new(root) {
    animation: 0.5s fade-in both move-in;
}

How it works

The View Transitions API creates a pseudo-element tree structure that handles the animation between states. The pseudo-element tree looks like this:

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

That’s all to enable cross-document transitions. Only CSS is required as the browser is triggered automatically when navigating between pages.

Basic setup for in-page transitions

In in-page transitions (SPA) the DOM structure change can be animated with View Transitions. This setup is very similar to the cross-document (MPA) transitions. Whereas the cross-document transitions are triggered by the browser when navigating between pages, in-page transitions are triggered by the application logic -> so we’ll need to bind it to an event / user action. This is gonna require a tiny bit of JavaScript code.

function startViewTransition(event) {
    // Check if the View Transitions API is supported by the browser
    if (!document.startViewTransition) return;
    
    document.startViewTransition(() => {
        updateDOM()
    });

    function updateDOM() {
        // update the DOM here by API reqest / client side logic
    }
}

Beside this JavaScript code, the rest of the setup is the same as for the cross-document transitions: at-rule for enabling view transition (@view-transition), CSS pseudo-elements (::view-transition-group(root), ::view-transition-image-pair(root), ::view-transition-old(root), ::view-transition-new(root)) for customizing the transition and applying animations (@keyframes).

Astro integration

Astro makes implementing view transitions even easier with its built-in <ViewTransitions /> component.

Basic setup in Astro

Add the component to your layout or individual pages:

<!-- src/layouts/Layout.astro -->
---
import { ViewTransitions } from 'astro:transitions';
---
<html>
  <head>
    <ViewTransitions />
  </head>
  ...
</html>

Customizing transitions

Astro provides several ways to customize transitions:

  1. Built-in animations:
<div transition:animate="slide">
  Content that slides
</div>
  1. Named transitions: As the name suggests, you can name your transitions. This is beneficial when you want to match the transition across pages as Astro will look for the transition with the same name on the old and on the new pages.
<header transition:name="hero">
  Matched across pages
</header>
  1. State persistence: Persisting the state comes useful when you want to maintain the state of the element across transitions so the element is not reset to its initial state.
<Counter client:load transition:persist />

link to the demo: Astro Image Gallery

This demo showcases:

Browser support and fallbacks

While the View Transitions API is relatively new, it’s designed to gracefully degrade. In Astro, you can control fallback behavior using the fallback prop:

<ViewTransitions fallback="animate" />

Options include:

Conclusion

The View Transitions API represents a significant step forward in web animations, making it easier than ever to create engaging page transitions. Whether used natively or through Astro’s excellent integration, it provides a powerful tool for improving user experience through smooth, animated state changes.

For more information, check out the following resources: