View Transitions API in Multi-Page Web Apps
The View Transitions API modernizes multi-page applications (MPAs) by providing a native mechanism to animate transitions between distinct HTML pages. Traditionally, smooth animations during navigation required complex Single-Page Application (SPA) architectures driven by heavy JavaScript routers. With the View Transitions API, developers can achieve seamless, app-like visual transitions across standard, server-rendered page navigations using minimal declarative CSS and native browser capabilities.
How It Works Across Documents
Cross-document view transitions operate during standard browser navigations, such as clicking a standard HTML link or submitting a form. When a navigation occurs between two pages on the same origin, the browser coordinates the snapshotting and rendering process:
Opt-in Activation: Both the active page and the destination page must opt in to cross-document transitions. This is configured in CSS using the
@view-transitionrule:@view-transition { navigation: auto; }Capturing the Old State: The browser intercepts the navigation, takes a visual snapshot of the outgoing page, and temporarily freezes the screen to prevent a white flash.
Fetching and Parsing the New State: The browser fetches and renders the incoming HTML document in the background.
Capturing the New State: Once the new document is parsed and rendered, the browser captures a snapshot of the incoming state.
Running the Animation: The browser constructs a temporary pseudo-element tree and transitions the visual elements from the old snapshot to the new snapshot using CSS animations.
The Pseudo-Element Tree
During a transition, the browser generates an overlay containing a dedicated pseudo-element structure at the root of the document:
::view-transition: The root overlay containing all active transitions.::view-transition-group(name): A wrapper representing a specific animated element.::view-transition-image-pair(name): Holds both the old and new visual states of the element.::view-transition-old(name): A static screenshot of the element from the outgoing page.::view-transition-new(name): A live representation of the element on the incoming page.
By default, the entire page (root) performs a cross-fade
transition. The outgoing view fades to opacity 0 while the
incoming view fades to opacity 1.
Customizing Shared Element Transitions
Developers can target specific UI components—such as headers, hero
images, or cards—to animate independently across page loads using the
view-transition-name property.
/* Page A and Page B */
.site-header {
view-transition-name: main-header;
}
.product-image {
view-transition-name: active-product;
}When an element on the outgoing page shares a
view-transition-name with an element on the incoming page,
the browser automatically interpolates their position, width, and
height. This allows a small thumbnail on a catalog page to smoothly
expand into a full-sized hero image on a detail page without client-side
routing.
Benefits for Modern Web Architecture
- Progressive Enhancement: In browsers that do not support the API, the browser falls back to the standard page-load lifecycle without breaking functionality.
- Reduced JavaScript Overhead: Visual fluidity no longer requires shipping complex client-side frameworks, virtual DOMs, or SPA routing libraries to handle page transitions.
- Performance: The browser handles the capture, layering, and animation natively, often utilizing hardware acceleration for smoother frame rates compared to manual JavaScript animations.