View transitions
I've wanted smoother navigation on this site for a while. For years the standard behaviour on a multi-page site is that you click a link, the old page disappears, and the new one snaps into place. The View Transitions API changes that, and for cross-document transitions the best part is that it only takes a few lines of CSS. Browser support is still maturing and the spec continues to evolve…
With great power… Jump to heading
When I first started reading about view transitions, it immediately brought me back to my early teens and the hours I spent editing websites and loading screens in Macromedia Flash. Remembering how chaotic some of those could get (though genuinely fun to make) was enough to make me want to set some ground rules for myself before I started experimenting.
It's easy to get carried away. The technical capability to animate between states doesn't automatically mean you should, at least not everywhere. A well-chosen transition reinforces the relationship between two states and gives the user a sense of where they are. A poorly chosen one, or too many of them, just adds friction and noise. The last thing I want is for navigating this site to feel like sitting through a Flash intro.
A few questions worth asking before adding transitions to everything:
- Does this transition help the user understand what changed or how two elements relate to one another?
- Or does it just look cool?
- Is the animation fast enough that it doesn't feel like a loading screen?
- Have you tested with
prefers-reduced-motiondisabled and enabled?
The default crossfade is actually quite tasteful and often all you need. Named transitions and custom animations are best reserved for moments where the visual continuity genuinely adds meaning, e.g. a shared element between two views, such as from a thumbnail to a hero banner, rather than a decorative flourish.
How it works Jump to heading
This post focuses on cross-document transitions, i.e. transitions that happen during navigation between separate page loads, since that's the relevant case for a static multi-page site like this one. There's also a same-document variant driven by JavaScript (more on that below).
For cross-document transitions, enabling them is as simple as adding this rule to your stylesheet on both the source and destination pages:
@view-transition {
navigation: auto;
}
That's it. The browser captures a snapshot of the current page, navigates to the new one, and crossfades between them. No JavaScript, no build step, no framework required.
Named elements Jump to heading
The default crossfade applies to the whole page, but you can get much more interesting behaviour by assigning view-transition-name to specific elements. When the browser finds a matching name on both pages, it animates that element independently, smoothly morphing it between its old and new position and size:
.post-banner {
view-transition-name: post-banner;
}
This is the approach I'm using on this site. The thumbnail image on the post listing page morphs into the full-width header image when you navigate to a post, giving the navigation a more connected feel.
One constraint worth knowing: view-transition-name values must be unique across the page at the time of the transition. If the same name appears on multiple elements, the transition for that element will be skipped. For list items you'll need to assign unique names in your templates or do it the old-fashioned way, i.e. manually. There's a newer view-transition-name: match-element that has the browser generate names automatically, but it's same-document only and won't work for cross-document transitions. Support for this is part of Level 2 of the spec and still rolling out.
Customising animations Jump to heading
The default crossfade can be overridden with CSS using the ::view-transition-old and ::view-transition-new pseudo-elements, giving you full control over each side of the transition independently. You can adjust timing, easing, and the animation itself.
I've skipped these for now on this site, and let the browser handle the details for me instead.
Same-document transitions Jump to heading
It's worth clarifying that cross-document and same-document refer to whether a navigation happens between two separate page loads or within a single one. They're not strictly tied to multi-page and single-page apps respectively. An MPA could in principle use same-document transitions too, e.g. when toggling UI state within a page.
For same-document transitions, you trigger them from JavaScript by wrapping any DOM update in document.startViewTransition(). This unlocks some additional capabilities: transition types, more granular lifecycle hooks via pageswap and pagereveal events, and tighter control over when and how transitions trigger. Many frameworks have first-class support for view transitions, and more are in progress. For a simple static site like this one, I find none of that complexity is needed.
Accessibility Jump to heading
Some browsers may skip cross-document transitions when prefers-reduced-motion is active, though this is browser behaviour rather than a formal guarantee from the spec. It's good practice to be explicit in your CSS, both to ensure consistent behaviour and to clearly signal intent. For cross-document transitions you can opt out entirely:
@media (prefers-reduced-motion: reduce) {
@view-transition {
navigation: none;
}
}
or opt in only if the user hasn't specified a preference:
@media (prefers-reduced-motion: no-preference) {
@view-transition {
navigation: auto;
}
}
For same-document transitions driven by JavaScript, the browser doesn't automatically suppress anything, so you're responsible for checking and branching yourself, either in JavaScript or by disabling the animations in CSS:
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none;
}
}
It's also worth noting that a preference for reduced motion doesn't necessarily mean the user wants no motion. Simple crossfades are generally considered safe. More complex or directional animations (slides, zooms, rotations) are where extra care is needed to avoid triggering any vestibular motion disorders or otherwise annoying your users.
Browser support Jump to heading
Cross-document view transitions are well supported in Chrome, Edge, and Safari, with Firefox support still in progress. The API degrades gracefully: if the browser doesn't support it, navigation just works as normal without the animation, so there's no need for a fallback. Same-document transitions have slightly broader support and reached Baseline Newly Available status in October 2025. See the resources linked below for current support details.
Limitations and things to watch Jump to heading
view-transition-namemust be unique per page at transition time, as mentioned earlier.- Stacking contexts: elements involved in a transition are promoted to their own layer, which can have unintended side effects on
z-indexand overflow. - The spec is still evolving. Level 2 introduces
view-transition-class,match-elementnaming, and improved type support, but not all browsers are up to date.
It's satisfying to get something like this working with so little code. I'll be watching browser support mature, particularly waiting for Firefox to catch up, and may play around more as the spec settles. For now, the default crossfade and the thumbnail/banner morph are more than enough for me.
Useful resources Jump to heading
- MDN - View Transitions API
- MDN - Using the View Transitions API
- Chrome for Developers - Cross-document view transitions
- web.dev - What's new in view transitions (2025 update)
- Jake Archibald - View transitions demo
- Can I Use - View Transitions API (cross-document)