The CSS transition property can’t animate a page change. It works on one element’s style at a time, and when a new document replaces the old one, there is nothing left to animate from.

The View Transition API handles that part. The browser takes snapshots of the old and new views and cross-fades them with CSS animations, and it works for updates inside a single-page app as well as for navigation between separate pages of one site.

Support depends on which kind you want. MDN Web Docs (2026) lists same-document transitions as Baseline since October 2025, while the @view-transition at-rule for cross-document navigation still carries a limited availability label.

What Are CSS Page Transitions?

See the Pen
Simple CSS3 Page Transition
by Paul DeCotiis (@decotii)
on CodePen.

Under the hood it’s a snapshot trick. The browser grabs the old view and the new view, then animates between them with CSS. MDN Web Docs describes the View Transition API as covering DOM changes inside a single-page app and navigation between separate documents in a multi-page app.

That gives you same-document transitions, which run inside one page, and cross-document transitions, which run between two pages of the same site.

It helps to keep the older property in perspective. The transition property moves one element between two style states, like a color change on hover. The View Transition API animates a whole view, or named parts of it, between two DOM states or two documents. And because the old document is gone before the new one paints, the transition property has no way to cover a full page change.

Most demo galleries under this keyword fake the effect. They stack panels, toggle classes and rely on a plain CSS animation to slide one block over another.

Before the API, a single-page app needed a pile of JavaScript just to position the old content, animate it out and remove it afterward, as MDN points out. Cross-document transitions weren’t possible at all.

How Does the View Transition API Animate a Page Change?

Capture, update, capture again. After that the browser plays a CSS animation on a tree of pseudo-elements laid over the page, and the default animation is a cross-fade.

The Snapshot Sequence

Chrome for Developers documents the order in a guide written by Jake Archibald and Bramus Van Damme.

What is shaping UX design today?

Uncover the newest UX design statistics: user behavior, design trends, ROI data, and insights driving better digital experiences.

Check Them Out →

The old state comes first, with snapshots of the root and every element that has a view-transition-name. Your callback then runs while rendering is suppressed. Once it finishes, the browser captures the result and builds the pseudo-element tree, and CSS animations play over the page until the live DOM becomes visible and interactive again.

Only one view transition runs at a time. If a second one starts mid-animation, the first skips to its end.

The Pseudo-Element Tree

The tree sits in an overlay above the page, so styling it never touches your real elements.

Pseudo-elementWhat it holds
::view-transitionThe overlay root that fills the viewport
::view-transition-group()One named transition, animating size and position
::view-transition-image-pair()Container for the old and new views
::view-transition-old()Static screenshot of the old view
::view-transition-new()Live render of the new view

This split is why video behaves oddly. The old view stays frozen while the new one keeps playing.

By default the old view fades from opacity 1 to 0 while the new view goes from 0 to 1.

Specification Levels

Two drafts from the W3C CSS Working Group define the feature, and MDN links both to the working group’s editor drafts as of its September 28, 2026 update.

Level 1 is the same-document side: document.startViewTransition(), view-transition-name and the pseudo-elements. Cross-document transitions live in Level 2, along with the @view-transition at-rule, view transition types and view-transition-class.

The pageswap and pagereveal events belong to neither CSS module. Chrome for Developers places them in the HTML specification.

How to Build a Same-Document Page Transition

See the Pen
Simple Page Transition
by Álvaro (@alvarotrigo)
on CodePen.

Chrome has supported document.startViewTransition() since version 111, per Chrome for Developers. Wrap your DOM update in it and the browser animates the change with a default cross-fade.

  1. Check that document.startViewTransition exists. If it doesn’t, run the DOM update directly and skip the animation.
  2. Pass the function that changes the DOM as the callback. Add or remove elements, switch classes or change styles inside it.
  3. Keep the callback short, since the page freezes while it runs. Do network fetches before the call. If you wait for fonts or images, use an aggressive timeout (Chrome’s guide caps the font wait at 100 ms).
  4. Style ::view-transition-old(root) and ::view-transition-new(root) with animation-duration or your own keyframes.
  5. Await updateCallbackDone, not ready, when app logic depends on the result. A skipped transition then can’t break the app.
function spaNavigate(data) {
if (!document.startViewTransition) {
updateTheDOMSomehow(data);
return;
}
document.startViewTransition(() => updateTheDOMSomehow(data));
}

Two failure modes are documented. Duplicate view-transition-name values on rendered elements skip the transition, and a callback that returns a rejected promise abandons it.

Chrome’s case study on redBus says view transitions made page-to-page navigation smoother and raised conversion rate in one of its user journeys.

Cross-Document Page Transitions With CSS Only

See the Pen
Page Transitions
by Álvaro (@alvarotrigo)
on CodePen.

Chrome has supported this since version 126 (Chrome for Developers). Add a @view-transition rule with navigation: auto to both pages and a same-origin link click animates with no JavaScript.

@view-transition {
navigation: auto;
}

Both documents need to share an origin, and both need the rule. No API call is involved, since the link click itself starts the transition.

The @view-transition At-Rule

A navigation that takes more than four seconds skips the transition in Chrome and throws a TimeoutError, according to Chrome for Developers.

Transitions run on traverse navigations, plus push or replace navigations that weren’t started through browser UI. Typing in the address bar, clicking a bookmark or reloading skips them.

Early experiments used a meta tag to opt in. Chrome calls that a temporary measure, and the CSS at-rule replaced it.

Customizing With pageswap and pagereveal

Both events fire for every same-origin cross-document navigation, whether or not a transition runs. The viewTransition property on the event exists only when one is about to play.

pageswap fires on the outgoing page before its last frame renders, so last-minute changes go there, before the old snapshots are taken. On the incoming side, pagereveal fires before the first render. That’s where you set names or transition types ahead of the new snapshots.

People use these events to name only the clicked list item just in time, or to pass data between pages through sessionStorage. skipTransition() is there for the cases where a transition makes no sense.

Register the pagereveal listener in a classic script in the head. Scripts loaded as modules, or with async or defer, can miss the first render unless marked blocking=render.

Google used cross-document view transitions to connect standard search with AI Mode, according to its August 2025 case study on Chrome for Developers.

Customizing the Animation: Names, Classes, Duration and Easing

See the Pen
Marionette – Region CSS Page Transitions
by Álvaro (@alvarotrigo)
on CodePen.

An element with its own view-transition-name animates on its own. view-transition-class groups similar ones, and the default fade can be swapped for keyframes, duration and easing on the old and new pseudo-elements.

Shared Element Transitions

See the Pen
Thumbnail to fullscreen page transition
by Steve Gardner (@ste-vg)
on CodePen.

A shared element transition links two different elements through one name. A product thumbnail grows into the hero image on the detail page because both carry the same name during the transition.

Names have to be unique within a rendered state, or the transition is skipped. The two elements don’t need to be the same DOM node. In a single-page app, set the name on the thumbnail just before the call and clear it inside the callback. If the aspect ratios differ, use object-fit: contain on the old view and cover on the new one.

Naming the header works the same way. It stays in place and cross-fades while the rest of the page slides, as in Chrome’s fixed-header demo.

Duration, Easing and Slide Effects

See the Pen
Slide Right Pure CSS Page Transition
by rafael correa (@correarafael)
on CodePen.

Chrome’s shared axis example pairs a 90 ms fade-out with a 300 ms slide, each with its own cubic-bezier easing (Chrome for Developers).

Both are defined with CSS keyframes and attached through the animation shorthand on the old and new root pseudo-elements.

view-transition-class applies one style rule to many named elements, so a card grid needs one selector instead of one per card. For direction, view transition types such as :active-view-transition-type(forwards) and backwards pick the slide. And when CSS can’t do something, like a circle that grows from the click position, the Web Animations API covers it.

Policybazaar raised the default animation duration to 0.4 s on one call-to-action transition, per Chrome’s e-commerce case study. Short durations suit page changes better than long, showy ones. Past half a second it starts to feel like waiting.

Which Browsers Support CSS Page Transitions?

Same-document transitions work in all three major engines (Chromium, WebKit and Gecko). Cross-document transitions are the uneven part, and MDN still rates the @view-transition at-rule as limited availability, not Baseline, in its April 20, 2026 revision.

Support by Browser and Version

BrowserSame-documentCross-document
Chrome and EdgeSupportedSupported
Safari18.018.2 (December 11, 2024)
Firefox144 (October 14, 2025)Not supported

Firefox 144 moved same-document transitions into Baseline as newly available in October 2025, according to MDN. Mozilla’s release notes for that version list the API and its CSS pieces for single-page apps, and nothing for cross-document navigation.

One cell in that table is contested. Some secondary guides claim Firefox supports cross-document transitions from version 132 or 144, while MDN and Mozilla’s own notes show no such entry. Treat those claims as unverified until MDN’s compatibility table changes.

A second conflict sits between two primary sources. Chrome’s cross-document guide, last updated April 14, 2024, lists Safari as unsupported for render blocking, while WebKit’s Safari 18.2 post says the release added blocking=render and link rel=expect.

The WebKit post is newer, so Safari counts as supported. Either way, check the update date on any support box before trusting it.

Detecting Support and Falling Back

A browser without support skips the animation and loads the page as usual.

With same-document transitions, the DOM update still runs and only the animation is missing. For cross-document, you get a normal page load, because the browser ignores an @view-transition rule it doesn’t recognize, like any unknown at-rule. Custom pseudo-element CSS never matches, so it does no harm.

That makes the animation an extra layer on top of working navigation. Test it as part of your cross-browser compatibility pass, with the animation absent, and confirm every link and DOM update still works.

Where CSS Page Transitions Hurt Performance and Accessibility

A transition hurts when the page stays frozen too long, and it hurts when motion plays for visitors who asked for less of it. Blocked rendering can also delay the first paint.

Performance Costs

The update step is the first cost. While your callback runs, the page is frozen, and web.dev rates an INP of 200 milliseconds or less as good and anything above 500 as poor, measured at the 75th percentile.

INP runs until the next painted frame after a click, tap or key press. A callback that holds the page frozen is therefore time the metric can count.

Then there’s layout. The default group animation changes width and height, which Chrome’s guide (updated September 25, 2024) says triggers layout on every frame. The planned fix hasn’t shipped yet.

Render blocking is the last one. Chrome advises against blocking=”render” by default unless you can measure the Core Web Vitals impact. MDN adds a useful lever here: a media attribute on link rel=expect lets narrow screens wait for less content than wide ones.

Prerendering With the Speculation Rules API

Prerendering gives a cross-document transition a loaded page to animate into.

Chrome’s prerender guide (updated January 23, 2026) reports near-zero LCP, lower CLS and better INP when a prerendered page activates. Prerenders stay same-origin by default, which matches the transition requirement, and a prerendered document fires pagereveal on activation (MDN).

The costs are real, though. Chrome caps immediate rules at 10 prerenders, and the browser treats each rule as a hint it can ignore. Single-page apps are out too, since in-app route changes can’t be prerendered.

Reduced Motion and WCAG

W3C classes Success Criterion 2.3.3, Animation from Interactions, at Level AAA. Sites aiming for AA are not required to meet it, but the criterion describes the right behavior for web accessibility.

Its definition of motion animation leaves out color and opacity changes that do not alter perceived size, shape or position. So the default cross-fade doesn’t count, but slides and growing images do.

The preference reaches CSS through a media query, and Chrome’s guide shows how to switch transitions off with it.

@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}

Chrome also notes that a reduced-motion preference does not always mean no motion. A subtler animation that still shows how elements relate is a valid choice.

Frameworks handle this differently, and the differences matter. Astro’s client router disables all view transition animations when the preference is detected. React doesn’t disable animations automatically, and its docs tell you to add the media query yourself. With Nuxt, experimental.viewTransition set to true skips transitions for reduced-motion users, while the value always leaves that decision to you.

Why a Page Transition Does Not Run

Most skipped transitions fail quietly. Nothing shows up on screen, and a short list of causes covers nearly all of them.

A hidden tab is the simplest. If the page visibility state is hidden when startViewTransition is called, the transition is skipped entirely (MDN).

Cross-document transitions need the navigation to be same-origin with no cross-origin redirect in the chain. If there is one, the activation property returns null.

Names left behind cause stranger bugs. A view-transition-name set in pageswap and never cleared returns from the back/forward cache, and the next pagereveal then creates duplicates. MDN’s fix is to reset names after the snapshots are taken.

Pseudo-element CSS is needed in the destination document only. A one-directional animation therefore needs the rules in both pages to cover the return trip.

Some browsers draw their own transition on swipe-back, and Chrome’s guide says to check hasUAVisualTransition before starting another. An operating system reduced-motion setting can also switch the animation off while everything else works.

Chrome DevTools covers most debugging. The Animations panel pauses the next animation so you can scrub through it, and the transition pseudo-elements appear in the Elements panel.

React has its own pitfalls, per its ViewTransition reference. A DOM node above the component stops enter and exit animations. Updates outside a Transition, Suspense or useDeferredValue never activate it. And animations from the legacy popstate event are skipped, so the back button stays still until the router uses the Navigation API.

CSS Page Transitions vs JavaScript Libraries and Framework Routers

Start with the native feature. Add a library only when you need an element to persist across pages or an animation in browsers that lack support.

ApproachJavaScript neededAnimates without native supportBest fit
Native cross-documentNoNo, plain loadSame-origin multi-page sites
Native same-documentOne callNo, update onlySingle-page apps
Barba.js or SwupYesYes, library animatesSites that need guaranteed motion
Framework routersYesVaries by frameworkApps already on that framework

Native View Transitions

Native transitions add no library weight and no script re-initialization, and the fallback is simply a normal page load. The downsides are uneven cross-document support and no way to keep a playing video or audio element alive across two separate documents.

Barba.js, Swup and GSAP

See the Pen
Kontext
by Hakim El Hattab (@hakimel)
on CodePen.

Barba.js uses PJAX. It blocks the normal link behavior, updates the URL with the history API, fetches the next page with an XMLHttpRequest, injects the new container, then removes the old one, according to its documentation.

Swup follows a similar idea. It intercepts clicks, loads the page in the background and replaces only the content containers. Before swapping, it waits for CSS animations, JavaScript animations and native View Transitions.

GSAP is an animation engine, not a router. Webflow made it free, including the former Club plugins, with a license that covers commercial use.

What you get from these tools is animation in any browser, plus prefetch and caching. The price is extra JavaScript and scripts that must re-run after each swap, and you now own the history handling.

Framework Routers

See the Pen
Material design transition
by David Marland (@djmarland)
on CodePen.

Astro’s ClientRouter component is opt-in, offers animate, swap and none fallbacks, and keeps elements such as a video playing through transition:persist. Astro’s own docs add that the router will become less necessary as browser APIs mature.

In SvelteKit, the onNavigate callback can return a promise, which is where document.startViewTransition fits. The docs warn against slow promises, because navigation then appears stalled.

Nuxt treats viewTransition as an experimental option, and the docs flag a known issue with data fetching in page setup, since transitions freeze DOM updates.

React’s ViewTransition component calls startViewTransition itself, so a hand-written call interrupts it.

My rule of thumb is to start with the native rule, check your analytics for the browsers you must cover, and reach for a library only when a persistent element or guaranteed motion justifies the added JavaScript.

CSS Page Transitions Examples To Check Out

Dummy Multi Layer Page Reveal Effect

See the Pen
Dummy Multi Layer Page Reveal Effect
by Mehmet Burak Erman (@mburakerman)
on CodePen.

Slide Up & Maybe Everything You Wanted

See the Pen
Vue2 page transitions with GSAP
by Rubber Ducky (@iamrubberducky)
on CodePen.

Easy Peasy CSS Page/Slide Transitions by Jamie Coulter

See the Pen
Easy CSS Page/Slide Transitions
by Jamie Coulter (@jcoulterdesign)
on CodePen.

Expanding Card Page Transition

See the Pen
Expanding card page transition effect
by Rachel Smith (@rachsmith)
on CodePen.

Tiles Page CSS Transition

See the Pen
Tiles Page Transition (CSS)
by Álvaro (@alvarotrigo)
on CodePen.

Jeff McCarthy’s Lollipop Transition

See the Pen
Lollipop Transition
by Jeff McCarthy (@jeffmccarthyesq)
on CodePen.

Layered Splash

See the Pen
Responsive bodymovin modal / page transition
by Jonas Sandstedt (@sandstedt)
on CodePen.

John Heiner’s Page Transition with Loader

See the Pen
Page Transition with Loader
by John Heiner (@johnheiner)
on CodePen.

Arsen Zbidniakov’s Page Transition Loader

See the Pen
Page Transition Loader
by Arsen Zbidniakov (@ARS)
on CodePen.

The Whole Screen Experience: Section Full-screen CSS Transitions

See the Pen
Fullscreen Layout Page Transitions – Pure JS/CSS
by Álvaro (@alvarotrigo)
on CodePen.

Muna’s Article Transition Magic

See the Pen
Article transition page
by Muna (@Munamohamed94)
on CodePen.

One Page, One Scroll: CSS Transformations by Nikolay Talanov

See the Pen
One page scroll navigation with css transforms
by Nikolay Talanov (@suez)
on CodePen.

Scroll & Reveal: Background CSS Page Transitions

See the Pen
Pagination & layout with clipped background div’s
by Álvaro (@alvarotrigo)
on CodePen.

Rotate & Revel: Svg Path Pagination by Nikolay Talanov

See the Pen
Svg path pagination and rotating page transition
by Nikolay Talanov (@suez)
on CodePen.

Back to Basics with a Twist: Basic Page Transition

See the Pen
Basic CSS Page Transition
by Álvaro (@alvarotrigo)
on CodePen.

Hexa-What? Hexagon Circle Magic

See the Pen
Hexagon Circle Panel Transition
by Ryan Mulligan (@hexagoncircle)
on CodePen.

Slide, Glide & Transform by Cassandra Rossall

See the Pen
transform: translate
by Cassandra Rossall (@cassandraPaige)
on CodePen.

Tiago Barros’ Slick Moves

See the Pen
Css Page Transition
by Tiago Barros (@limadeabrros)
on CodePen.

The Mesmerizing World of 3D: Split 3D Carousel

See the Pen
Split 3D Carousel
by Paul Noble (@paulnoble)
on CodePen.

Dive into Parallax: Fullscreen Drag-slider

See the Pen
Fullscreen drag-slider with parallax
by Nikolay Talanov (@suez)
on CodePen.

Fancy Schmancy Cubic Moves 

See the Pen
GSAP Cubic bezier page transition
by Álvaro (@alvarotrigo)
on CodePen.

The Classic Wipe Revamped: TOMAZKI’s Take

See the Pen
Page transition CSS3
by TOMAZKI (@Podgro)
on CodePen.

One Page, Many Wonders: Pure CSS Vertical Navigation

See the Pen
Pure CSS One page vertical navigation
by Hrtzt (@hrtzt)
on CodePen.

Go Skewed or Go Home

See the Pen
Skewed One Page Scroll
by Nikolay Talanov (@suez)
on CodePen.

Slide into the Future

See the Pen
CSS Page Transitions
by Álvaro (@alvarotrigo)
on CodePen.

Text, Shapes, Colors: Full Page Scroll Animation

See the Pen
Full Page Scroll Animation Transition
by Tyler Chipman (@tyler-chipman)
on CodePen.

Minimal but Mighty: Folio’s Signature Move

See the Pen
folio.transitions
by Foliodot (@foliodot)
on CodePen.

The Casual Coolness of CSS UI

See the Pen
Just another CSS UI
by Jamie Coulter (@jcoulterdesign)
on CodePen.

CSS Page Transitions FAQ

Do page transitions affect SEO?

Neither MDN nor Chrome documents any ranking effect. Cross-document transitions leave each page a normal document with its own URL, and Astro’s docs say they do not alter core multi-page behavior.

The indirect risk is speed, because a slow update step hurts responsiveness metrics.

Can a page transition run between two different domains?

No. Chrome limits cross-document transitions to same-origin navigations, so a move from developer.chrome.com to www.chrome.com fails because the hostnames differ.

MDN notes the restriction could be relaxed in future implementations.

Does the back button play the transition in reverse?

Not automatically. A slide that moves right to left on every navigation feels wrong when the visitor goes back, as Chrome’s guide points out.

Use view transition types to assign a backwards animation, and set a type for each direction.

Do Webflow and WordPress sites support page transitions?

Yes, because the cross-document rule needs only CSS and no JavaScript. Webflow lists a CSS-only cloneable demo that animates where cross-document transitions are supported and loads normally elsewhere.

WordPress serves full pages from one origin, so a rule in the theme stylesheet reaches both documents.

Rolling Out CSS Page Transitions Safely

Ship the default cross-fade first and measure it in the field before adding any custom motion. That order keeps failures cheap, since the default animation adds the least work to each page load.

Opt both pages into the cross-fade, then compare real-user INP and LCP before and after. If the numbers hold, add shared elements, then types, then render blocking.

Render blocking goes last because Chrome advises measuring its Core Web Vitals cost and Safari supports it as well, so one field measurement per browser decides whether it stays.

This advice changes the day Mozilla lists @view-transition in a Firefox release note. The position was verified against MDN and Mozilla’s notes on October 13, 2026.

Draft the keyframes for the custom motion step with a CSS animation generator before wiring them to the root pseudo-elements.

Bogdan Sandu
Latest posts by Bogdan Sandu (see all)