Animate page changes with view transitions
You'll build a grid of colors where clicking a tile grows it into the full swatch on the next page. Back shrinks it home again. It's the browser's own View Transitions API, driven by the navigator fsr already uses for client navigation. It takes one option and one CSS property.
Before you start
Install from crates.io. You need no Node and no package manager.
cargo install snapfire_compiler
cargo install snapfire_fsr_cli
fsr --version
Every command and screenshot on this page was captured with fsr 0.x.
A list and a detail page#
The colors, in app/src/colors.ts:
;
;The index lists them as tiles:
;
;
;
;
Each color gets a page with one big swatch:
;
;
;
;
;
Look at the two viewTransitionNames. The tile for Lagoon on the index and the swatch on /color/lagoon are both called swatch-lagoon. That shared name is the whole trick: it tells the browser they're the same thing in two places.
Some layout, at the end of app/styles/app.css:
}
}
}
}Turn transitions on#
The scaffold's app/src/main.ts already starts the navigator, which swaps pages without a full reload when a Link is clicked. Give it one option:
;
;
;
;
;Open http://127.0.0.1:3000 and click Lagoon. The teal tile grows out of its grid cell into the wide swatch while the rest of the page crossfades to the detail page. Press Back and it shrinks into its cell again.
This site's navigator runs with transitions: true, so the tiles above behave the way yours will. Click one, then press Back.
What happened#
With transitions: true the navigator does its usual swap inside document.startViewTransition. The browser takes a picture of the old page. The navigator puts the new one in and the browser animates between the two. Without any names that's a crossfade of the whole page. An element with a view-transition-name gets its own animation from where it was to where it is, so swatch-lagoon moves and resizes from the tile's box to the swatch's.
The pages are still rendered by the server. The navigator fetches the next page's payload, the same request it makes with transitions off, so nothing about loading or data changes. The animation is all CSS in the browser.
Who doesn't see it#
The navigator skips the transition when the visitor's system asks for reduced motion, when the browser has no View Transitions API and when the tab is hidden. The page still changes; it just changes at once. Only a navigation animates, so a refresh after an action doesn't.
Try it#
Turn on reduced motion in your system settings or in the browser's rendering tools, then click a tile. You land on the color page with no animation.
Then turn it off for one link. Change the "All colors" link on the color page to:
That link now swaps without animating, while every tile on the index still grows. The opposite works too: leave enableNavigation() with no options and put data-sf-transition on just the links that should animate.