Home / Snippets / Animation /

Page fade transition

Smooth page-level fade using the View Transitions API.

Page content

Widely Supported
animationview-transitions

Quick implementation

/* Opt in to cross-document view transitions */
@view-transition {
  navigation: auto;
}

/* Customize the fade animation */
::view-transition-old(root) {
  animation: fade-out 0.3s ease-out;
}

::view-transition-new(root) {
  animation: fade-in 0.3s ease-in;
}

@keyframes fade-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 0s;
  }
}

Prompt this to your LLM

Includes role, constraints, and edge cases to handle.

You are a senior frontend engineer adding page transitions to a multi-page site.

Goal: Add a smooth fade transition between page navigations using the CSS View Transitions API.

Technical constraints:
- Use @view-transition { navigation: auto } to opt in to cross-document transitions.
- Customize ::view-transition-old(root) and ::view-transition-new(root) pseudo-elements.
- Use short durations (200–400ms) — page transitions should feel snappy, not cinematic.
- Include prefers-reduced-motion to disable or shorten animations.
- This works for multi-page apps (MPA) — no JavaScript framework needed.

Edge cases:
- Safari support landed in 2024 — test across browsers.
- The old and new page snapshots are composited images — interactive elements are frozen during transition.
- Fallback: if view transitions aren't supported, navigation works normally with no fade.

Why this matters in 2026

For years, smooth page transitions were exclusive to single-page apps. The View Transitions API brings them to plain multi-page sites with zero JavaScript. Add two CSS rules and your site gets native cross-fade transitions between pages. This is the single biggest UX upgrade you can add to a static site in 2026.

The logic

When a navigation occurs, the browser captures a screenshot of the old page and the new page. It creates ::view-transition-old(root) and ::view-transition-new(root) pseudo-elements for these snapshots, then cross-fades between them. By default, the browser does a simple opacity cross-fade. You can customize the animation with your own @keyframes — or even animate position, scale, and clip-path for more complex transitions.

Accessibility & performance

View transitions are composited by the browser — they don't block the main thread or delay page load. The transition happens in a separate compositing layer, so the new page can start loading while the animation plays. For accessibility, always respect prefers-reduced-motion by setting animation-duration: 0s, which keeps the transition instant without breaking the API.