Like anyone, I love a good “native-feeling” experience on the web. I’ve really enjoyed creating that vibe with the new View Transitions API. Luckily it’s is pretty clean to work with, both with the Astro framework, and out of the box!
View Transition Options
Transitioning UI between states has been something that developers have been doing for ages, and yes, you can use things like the Web Animation API as well as CSS transitions and animations for that. But, handling transitions when elements are removed from the page, or you navigate away from a given page, is much harder, particularly when you’re thinking about assistive tech, scroll position, and focus… it’s gnarly.
Untiiiiil now! The View Transitions API has been evolving in the browser both as a proper W3C Candidate Recommendation, and as of this week, the draft for cross-document navigation is in a public working draft!
What does that mean? It means you can have that “native” animation experience, right in the browser! But more specifically, currently you can use the View Transitions API:
- For transitions on normal page-to-page loading
- For transitions on a single page application (SPA)
- For transitions of the DOM changes without a page change
View Transitions + Astro
My favorite way to actually see this implemented so far is using the Astro framework. They have a really great API that allows you to use View Transitions on a single page, or turn on “SPA mode” and navigate across your entire application and have transitions between pages and elements.
Out of the box, Astro supports:
- Out of the box animations like
fade
andslide
- Navigation forwards and backwards
- Support for
prefers-reduced-motion
- And moooore
Using View Transitions in Astro
Adding the View Transitions API to an Astro page is just two lines of code: importing it in your frontmatter, and adding it to the <head>
.
---
import { ViewTransitions } from 'astro:transitions';
---
<html lang="en">
<head>
<!-- ... -->
<ViewTransitions />
</head>
<body>
<!-- ... -->
</body>
</html>
Code language: HTML, XML (xml)
If you put these lines in a layout component that’s shared across pages, that automatically enables View Transition-powered client-side navigation, fading between pages.
Astro automatically corresponds elements between two pages by their type and location within the DOM, so if you want something simple, this is all you need!
Customize more with directives
You can have more fine-grained control of what your transitions do by using the transition:*
directives.
transition:name
overrides the default matching that Astro does between elements. Make sure when you use this one, you use unique names, kind of like anid
.transition:animate
overrides the default fade animation, and you can customize what animations you want.transition:persist
overrides how Astro replaces elements across pages and lets you persist components and elements across pages.
Example
I built a little demo for you to see the View Transitions API in action!
There’s two main pages to make this little “city directory” site, index.astro
, and [city].astro
, which pull from a locations.json
file.
In index.astro
, we loop through the locations:
<ul>
{locations.map((city) => {
return (
<li>
<span transition:name={`${city.emoji} emoji`}>{city.emoji}</span>
<a href={`/city/${city.city.toLowerCase()}`} transition:name={`${city.city} link`}>
{city.city}, {city.country}
</a>
</li>
)
})}
</ul>
Code language: JavaScript (javascript)
In this, note the two transition names on the emoji and on the link, unique for each city.
In [city].astro
(which is a dynamic route generated per city), we map those transition names to different elements:
<h2 transition:name={`${city} link`}>{city}, {country}</h2>
<p>
<span transition:name={`${city} emoji`}>{emoji}</span> {description}
</p>
Code language: HTML, XML (xml)
So now, when we navigate between the home page and a city page (and back), the heading transitions from the link, and the emoji moves from the link to the paragraph!
Using View Transitions without Astro
If your framework of choice is not Astro, but you still want to try out the View Transitions API, it does work in Chrome, Edge, and Opera right now out of the box (Safari and Firefox require polyfilling).
You can check out the documentation here. It’s a bit more manual when you want to build with it from scratch, but you do get a lot of control!
Here’s a very basic example of transitioning between some text values with the API:
Note that the CSS lets you control the transition, similar to how traditional CSS animations work! You assign an animation with view-transition-name
, and then you give the view transition pseudo-elements get assigned animations in and out (via ::view-transition-old
and ::view-transition-new
)!
Read more
This is just scratching the surface of what the View Transitions API can do! You can find some more resources here:
You can improve your demo by adding
max-width: fit-content
to the headlines on the city pages.Currently it scales to the block element with 100% width and it looks a bit janky:
[Paris, France]
↓
[Paris, France ]