CODE CRISPIES

View Transitions API — SPA-Feel Without an SPA

3 min read cssnavigationperformance

The reason teams reach for SPAs is rarely the architecture. It's the feel: nothing flashes white between pages, the previous content fades out, the new one fades in. View Transitions give a regular multi-page site that exact behavior — no JavaScript framework required.

Cross-document view transitions in two lines

@view-transition {
  navigation: auto;
}

That single rule, on every page of your site, opts the navigation into transitioned page swaps. The browser captures the old page, navigates, then animates the cross-fade to the new one. Default duration ~0.25s.

That's it for the baseline. The page-flash is gone.

Naming elements that should morph

<!-- on the listing page -->
<a href="/posts/native-popover">
  <article class="card" style="view-transition-name: card-popover">
    <h2>Native Popovers</h2>
    <p class="excerpt"></p>
  </article>
</a>

<!-- on the post page -->
<article class="hero" style="view-transition-name: card-popover">
  <h1>Native Popovers</h1>
  <p class="excerpt"></p>
</article>

The browser sees the same view-transition-name on both pages and animates the rectangle from old position/size to new. Hero animations between routes — no React Router shared element, no Framer Motion. Just an attribute.

Customizing the transition

@view-transition {
  navigation: auto;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.4s;
  animation-timing-function: cubic-bezier(0.32, 0.72, 0, 1);
}

/* Specific element transitions inherit naming */
::view-transition-old(card-popover) {
  animation-name: slide-out-left;
}
::view-transition-new(card-popover) {
  animation-name: slide-in-right;
}

@keyframes slide-out-left {
  to { transform: translateX(-100%); opacity: 0; }
}
@keyframes slide-in-right {
  from { transform: translateX(100%); opacity: 0; }
}

::view-transition-old(name) and ::view-transition-new(name) give you the snapshot pseudo-elements for any named region. Style them like normal — animations, filters, transforms.

Caveats

Browser support (2026-05)

For Firefox users, the navigation works exactly as before — no transition, but no breakage. Pure progressive enhancement.

When not to use it

What this replaces

Before view transitions, achieving SPA-feel on a multi-page site meant Turbolinks / Hotwire or a full SPA framework. View Transitions is the platform doing it natively, with a strict subset of the API surface needed to ship the feature.

I removed Turbo from a small marketing site and dropped the JS bundle by 35 KB. Same UX. The platform finally caught up.


Practice modern CSS at Code Crispies — interactive lessons with live preview cover transitions and animations.