Supercharge your app's animation with View Transitions
- Geoff Rich Senior Software Engineer, Ordergroove | Svelte Core Team
View Transitions is an exciting new browser API that streamlines the process of animating between two page states. While the headline use case is page transitions, it can also be used for all sorts of animation in your app. In this talk, I’ll show how you can use this API to replace Svelte’s animation primitives — and beyond.
Transcript
Hello, I'm Geoff, a Svelte maintainer and senior software engineer at OrderGroove.
Svelte transitions in animations.
Everybody loves them.
In fact, they're usually one of the top three reasons people fall in love with Svelte, right
next to simple state management and feeling superior about not having a virtual DOM.
There are seven built-in Svelte transitions and one built-in animation function, but today
we're going to focus on two, Flip and Crossfade.
We'll talk about why we need them in the first place, and how new browser capabilities might
provide an alternative.
Maybe.
Let's start with animate-flip.
This is a directive that you can use inside an each block to make reordering the elements
in that block smoother.
For example, look at this row of playing cards.
Clicking this button reorders them, but they abruptly jump to their new positions, and
it's hard to understand what playing card moved where.
But if I add animate flip to the individual DOM elements, they instead animate their new
position, which is much nicer.
It's worth noting that you do need to provide a key in your each loop, otherwise Svelte
can't tell which card moved where.
This is something you could implement in JavaScript, but you have to grab the DOM elements yourself
and it gets a bit mathy, so it's nice that Svelte makes it as simple as adding a single
attribute.
But Svelte's flip only works in individual each blocks.
In this demo, you can also click a card to select it and move it to a separate row.
Here's what that looks like.
If I want that transition to be animated, I need to reach for a different tool, the
crossfade transition.
First, we call crossfade to get the pair of transitions, and then apply them to the elements
in each row.
where we apply it to the first row, and then the second. We pass a unique key so Svelte knows that
when we remove an element from here, it's the same as the element we're adding down here,
and should be animated to its new position. In this case, the key is the card's suit and rank,
so for this card, the key is the string 10 hearts. Once we apply the transition,
swapping the card will animate it to its new position.
And we can now shuffle between rows too.
If you haven't seen these before, go take a look at the official Svelte tutorial.
They are pretty fundamental bits of Svelte API,
so I'm not going to dwell on the particulars for much longer.
So Svelte's flip and crossfade directives were introduced in 2019.
Are there more options for animating UI states on the web in 2023?
Well, yes. Let's talk about the view transition API.
The View Transition API has been developed in Chrome for a while now.
You may have heard about it under its previous name, Shared Element Transitions.
According to the API explainer, it "makes it easy to change the DOM in a single step
while creating an animated transition between the two states."
Up to this point in browser history, we had the tools to animate individual elements,
but smoothly transitioning elements between two UI states was still a hard problem, and
And people often reach for libraries to solve it.
So this API introduces a new document method, startViewTransition.
When you call it, it will start a view transition and capture the current state of the page.
Inside a callback passed to the function, you update the DOM somehow.
And once you're finished, it will capture the new state of the page, and then smoothly
transition between the old and new states.
By default, it will fade the old state out while fading the new state in, but you can
customize the transition in CSS, just like you would any CSS animation. In addition,
this API also introduces a new "viewTransitionName" CSS property, and you'll see how we use this
in a bit. I'm barely scratching the surface here, so check out the official explainer
for a much more detailed rundown.
Let's look back at the demo we were working on before. How can we refactor this code to
use startViewTransition instead of Svelte's animateFlip and crossfade? I've reverted back
to before we added those functions, so we have a blank slate.
Let's look at the shuffle functionality.
To have shuffling trigger a view transition, we can wrap the actual state updates inside
of startViewTransition.
The browser then needs to know when the DOM has finished updating.
In Svelte, we can do that by awaiting the tick function.
So with that, every time we shuffle, we have a transition happening.
A fade.
But that's not quite what we want, is it?
This is because the browser only sees the old and new states, it doesn't know whether
a card moved somewhere or was replaced.
Just like Svelte needed a key, so does the browser, which we can do by setting a view
transition tag on the element.
Since this tag needs to be unique, I like to use a CSS custom property to inject the
dynamic part of the transition tag.
We can set the prop in a style directive, and then use it in our CSS.
Like before, I can use the name of the card to make up the key, which is unique for this
demo.
And with that, the cards animate during shuffle.
I want to pause for a moment to call out just how cool this is.
We have elements dynamically moving to their new positions, and there's no JavaScript code
doing calculations to make this happen.
We didn't have to write it, and neither did Svelte.
The browser is figuring it out for us.
So should you go out and yank all the animate-flip and transition-crossfade from your codebase
in favor of this new browser API?
Well, not necessarily.
Each version has their pros and cons.
Let's compare them.
Let's start with the pros of the Vue Transition version.
First, as I mentioned, the browser does all the heavy lifting.
You're also able to use CSS to customize the animation, which is especially useful if you
want to use media queries, say to target different device sizes or reduced motion preferences.
And because it's CSS animation, you can easily debug the animations using Chrome's Animation
DevTools.
Also, there aren't any Svelte templating constraints.
With AnimateFlip, we had to be in an each block.
But the View Transitions API doesn't care about that.
This one probably isn't significant enough to matter, but we do ship slightly less client-side
JavaScript since we don't need to include Svelte's flip or crossfade code.
And because it's a browser API, the knowledge is portable.
You can't use Svelte animations and transitions in other frameworks, but you can use view
transitions.
On the other hand, it also comes with some cons.
It only works in Chrome, at least for now.
While animation is a good progressive enhancement case, if this is broken, then your app should
still work.
Using this animation completely in non-Chrome browsers may be a dealbreaker.
Hopefully, this won't always be a con as the API is implemented by more browsers.
Until then, make sure to check the API is supported before using it.
And while we can use CSS to customize the animation, targeting the animation for multiple
elements can get wordy.
If we wanted to change the animation duration for all of the cards, we would need to write
a selector for every transition name we use.
There is a proposal to solve this problem by creating classes of transition groups,
but that isn't implemented right now.
Finally, we have to wrap every function that triggers viewTransition in document.startViewTransition,
so if we also want swapping a car to transition too, we need to wrap it.
Spell transitions are more declarative in that you can add them to the element directly,
and any state affecting that element will trigger the transition.
So while view transitions are great, they're not a drop-in replacement for the Svelte transitions
you're already familiar with, and they're not really meant to be.
They solve similar problems, but in different ways, with different tradeoffs.
We didn't even talk about animated page transitions, arguably the headline feature of the view
transition API, and something that is tricky to do with Svelte's transitions today.
Some of the cons I mentioned become much less relevant with the page transition use case.
For example, for SvelteKit page transitions, you don't have to wrap every link that should
trigger a transition.
You only have to wrap a single navigation lifecycle hook.
As much as we all love Svelte, it's important to also know about the web platform's APIs.
There may come a point where Svelte is dead and gone, but the web platform is extremely
backwards compatible, and browser APIs and fundamentals are here to stay.
There's a good chance that view transitions will become an essential tool in your tool
belt for years to come, especially as they gain wider cross-browser adoption.
If you want to read more about Svelte and Vue transitions, head to my blog at geoffrich.net,
where I'll have a written version of this talk as well as links to some further reading.
I also recommend checking out my post on creating animated page transitions in SvelteKit using
the Vue Transition API.
Thanks for your time, and enjoy the rest of the talks!