CSS ::view-transition Pseudo-Element
The ::view-transition pseudo-element represents the top-level overlay created during a View Transition. It contains the pseudo-elements used to animate between the old and new visual states of a webpage, allowing developers to control how transition content is displayed above the normal document.
Syntax
::view-transition {
property: value;
}
The ::view-transition pseudo-element represents the root of the generated View Transition overlay.
It does not accept arguments or require parentheses.
For example:
::view-transition {
z-index: 100;
}
This sets the stacking order of the transition overlay.
The overlay exists only while an active View Transition is being rendered.
To style individual transition images or groups, use the related View Transition pseudo-elements:
::view-transition-old(root) {
animation-duration: 400ms;
}
::view-transition-new(root) {
animation-duration: 400ms;
}
These rules target the old and new visual snapshots of the document's root transition group.
The root argument refers to the default transition name for the document's root element.
How It Works
The View Transitions API allows browsers to animate visual changes between two document states.
During a transition, the browser captures the relevant old visual state, updates the document, and creates a new visual state.
It then generates a temporary overlay containing the transition's visual representations.
The ::view-transition pseudo-element is the root of that overlay.
The process generally follows these steps:
- A View Transition is started through JavaScript or an eligible cross-document navigation.
- The browser captures the old visual state of participating elements.
- The document changes or the new document becomes available.
- The browser prepares the new visual state and generates the transition pseudo-element tree.
- CSS animations display the transition between the old and new states.
- When the transition finishes, the temporary pseudo-elements are removed.
The transition overlay is displayed above the ordinary document content.
The underlying HTML elements remain part of the document. The generated pseudo-elements are temporary visual representations used for animation.
The ::view-transition pseudo-element does not start an animation by itself.
A transition must first be initiated using a supported mechanism.
View Transition Pseudo-Element Tree
When a View Transition is active, the browser creates a hierarchy of pseudo-elements.
The ::view-transition pseudo-element is the outermost container.
A simplified structure looks like this:
::view-transition
::view-transition-group(root)
::view-transition-image-pair(root)
::view-transition-old(root)
::view-transition-new(root)
Each pseudo-element has a different purpose.
| Pseudo-Element | Purpose |
|---|---|
::view-transition |
Represents the top-level transition overlay. |
::view-transition-group() |
Groups the transition images for a named element. |
::view-transition-image-pair() |
Contains the old and new visual representations. |
::view-transition-old() |
Represents the old visual state. |
::view-transition-new() |
Represents the new visual state. |
A page can have multiple transition groups when different elements have distinct view-transition-name values.
All of these groups are contained within the same top-level transition overlay.
For example:
::view-transition-group(root) {
animation-duration: 500ms;
}
::view-transition-group(card) {
animation-duration: 300ms;
}
The first rule styles the root transition group.
The second rule styles a transition group named card.
Both groups are descendants of the ::view-transition overlay.
Starting a View Transition
For changes within the same document, a View Transition can be started using the JavaScript document.startViewTransition() method.
For example:
document.startViewTransition(() => {
document.body.classList.toggle("alternate");
});
The callback updates the document by toggling the alternate class.
The browser captures the old and new visual states and animates between them.
The method returns a ViewTransition object that provides promises for tracking the transition.
To provide a fallback for browsers without the API:
function updatePage() {
document.body.classList.toggle("alternate");
}
if (document.startViewTransition) {
document.startViewTransition(updatePage);
} else {
updatePage();
}
In supporting browsers, the update is animated.
In unsupported browsers, the class changes immediately without a View Transition.
The CSS ::view-transition rule only affects the temporary overlay created when the transition runs.
Styling the Transition Overlay
The ::view-transition pseudo-element represents the outermost transition container.
It is generated with browser-defined styles that position it over the document and establish its stacking behavior.
For example:
::view-transition {
z-index: 100;
}
This explicitly sets the overlay's stacking order.
Because the overlay is already placed in the browser's top layer, a custom z-index is usually unnecessary.
Most visual animation customization should target the nested transition pseudo-elements instead.
For example:
::view-transition-old(root) {
animation-duration: 500ms;
}
::view-transition-new(root) {
animation-duration: 500ms;
}
These rules control the animation duration of the old and new root snapshots.
Changing the outer overlay's layout or positioning can interfere with the browser's transition rendering.
For most projects, leave the overlay's default positioning intact and customize the transition groups or images.
The view-transition-name Property
The view-transition-name property identifies elements that should participate in a View Transition as separate visual groups.
For example:
.card {
view-transition-name: featured-card;
}
This assigns the name featured-card to the element.
During an active transition, the browser can generate a group for that name:
::view-transition-group(featured-card) {
animation-duration: 400ms;
}
The corresponding old and new images can also be styled:
::view-transition-old(featured-card) {
animation-duration: 400ms;
}
::view-transition-new(featured-card) {
animation-duration: 400ms;
}
Each participating element must have a unique transition name within a given document state.
Using the same non-none name on multiple rendered elements can prevent the transition from running correctly.
The root element normally participates using the default name root.
To prevent an element from participating as a separate named transition group:
.card {
view-transition-name: none;
}
The element may still appear as part of an ancestor's captured snapshot.
The view-transition-name property controls participation, while the ::view-transition pseudo-element represents the overall transition overlay.
Example
The following example uses the View Transitions API to animate a card between two visual styles.
Click the button to switch the card's background color, text color, and border radius.
HTML:
<div class="view-transition-demo">
<div class="transition-card">
<strong>CSS View Transitions</strong>
<p>Animate changes between visual states.</p>
</div>
<button type="button" id="transition-toggle">Change Appearance</button>
</div>
CSS:
.view-transition-demo {
max-width: 300px;
}
.view-transition-demo .transition-card {
padding: 20px;
border-radius: 6px;
background-color: #0066cc;
color: #fff;
view-transition-name: demo-card;
}
.view-transition-demo .transition-card p {
margin: 8px 0 0;
color: inherit;
}
.view-transition-demo.is-alternate .transition-card {
border-radius: 24px;
background-color: #333;
color: #fff;
}
.view-transition-demo button {
margin-top: 12px;
padding: 8px 14px;
border: 0;
background-color: #0066cc;
color: #fff;
cursor: pointer;
}
::view-transition {
z-index: 100;
}
::view-transition-group(demo-card) {
animation-duration: 500ms;
}
JavaScript:
const demo = document.querySelector(".view-transition-demo");
const button = document.querySelector("#transition-toggle");
button.addEventListener("click", () => {
const update = () => demo.classList.toggle("is-alternate");
if (document.startViewTransition) {
document.startViewTransition(update);
} else {
update();
}
});
Animate changes between visual states.
Try it: Click Change Appearance to switch between the two card styles.
In supporting browsers, the card animates between its old and new appearances.
The browser creates the ::view-transition overlay and a named transition group for demo-card.
The ::view-transition-group(demo-card) rule sets the animation duration to 500 milliseconds.
The ::view-transition rule demonstrates how the overlay's stacking order can be styled.
In browsers without View Transitions support, the button still changes the card's appearance immediately.
Note: The animation is intentionally limited to the demonstration card. The rest of the page remains unchanged.
Customizing Transition Animations
View Transitions provide default animations, but developers can customize them using the generated pseudo-elements.
For example, the old image can fade out while the new image fades in:
@keyframes fade-out {
to {
opacity: 0;
}
}
@keyframes fade-in {
from {
opacity: 0;
}
}
::view-transition-old(root) {
animation: 300ms ease-in both fade-out;
}
::view-transition-new(root) {
animation: 300ms ease-out both fade-in;
}
The first animation gradually hides the old snapshot.
The second animation reveals the new snapshot.
Both images are rendered within the ::view-transition overlay.
To target a named transition group instead of the entire page:
::view-transition-old(featured-card) {
animation: 300ms ease-in both fade-out;
}
::view-transition-new(featured-card) {
animation: 300ms ease-out both fade-in;
}
This applies the fade animations only to the group named featured-card.
The top-level ::view-transition pseudo-element remains the common container for all transition groups.
Cross-Document View Transitions
View Transitions can also animate navigation between different documents on the same origin.
Unlike same-document transitions, eligible cross-document transitions do not require calling document.startViewTransition().
Instead, both participating documents can opt in using the @view-transition at-rule:
@view-transition {
navigation: auto;
}
This enables eligible same-origin navigation transitions in supporting browsers.
For example, two pages on the same website can use the same rule to allow animated navigation between them.
Both pages can also assign matching transition names to corresponding elements:
.site-logo {
view-transition-name: site-logo;
}
The browser can use those names to animate matching elements between the outgoing and incoming documents.
Cross-document View Transitions are subject to browser eligibility rules and may be skipped in certain navigation situations.
The ::view-transition overlay is still used to display the generated transition imagery.
For more advanced transitions, the View Transitions API also provides events and transition types that can be used to customize navigation behavior.
Supported CSS Properties
The ::view-transition pseudo-element is a generated overlay box and can be styled using applicable CSS box and layout properties.
However, the browser supplies important default positioning and stacking behavior that should generally be preserved.
| Property | Purpose |
|---|---|
z-index |
Controls stacking order within the overlay's stacking context. |
position |
Controls positioning, although changing the default may disrupt the overlay. |
inset |
Controls offsets for a positioned overlay. |
width and height |
Control box dimensions, although the default viewport coverage should usually remain unchanged. |
background-color |
Sets a background on the overlay. |
pointer-events |
Controls pointer interaction with the overlay. |
For example:
::view-transition {
z-index: 100;
}
For animation-specific properties such as animation-duration, animation-timing-function, and animation-name, developers generally target the nested transition groups or image pseudo-elements.
For example:
::view-transition-group(featured-card) {
animation-duration: 400ms;
}
This is usually more useful than changing the dimensions or positioning of the outer overlay.
Limitations
The ::view-transition pseudo-element has several important limitations.
- It exists only while a View Transition is active.
- It does not start a transition by itself.
- It does not permanently change the document's HTML or CSS layout.
- It cannot be used to select ordinary document elements.
- It depends on browser support for the View Transitions feature.
- Changes to its default positioning or layout may interfere with rendering.
- Transitions can be skipped or interrupted by navigation, document changes, or browser restrictions.
- Named transition elements must satisfy the uniqueness requirements of
view-transition-name. - Cross-document transitions have additional eligibility and navigation requirements.
For example, this CSS alone does not create a transition:
::view-transition {
z-index: 100;
}
The browser must first initiate a View Transition before the overlay exists.
Use feature detection and provide a nonanimated fallback for browsers that do not support the API.
Accessibility Considerations
View Transitions can improve visual continuity, but animations should remain comfortable and predictable for users.
Follow these accessibility practices:
- Respect the user's reduced-motion preference.
- Avoid rapid flashing, excessive movement, or distracting animations.
- Keep transitions short enough that navigation and interaction remain responsive.
- Ensure content remains usable when transitions are unsupported or disabled.
- Preserve keyboard focus and logical navigation order during document updates.
- Do not use animations as the only way to communicate changes.
- Test transitions with keyboard navigation and assistive technologies.
- Keep interactive controls available and understandable after the transition.
For example, use the prefers-reduced-motion media query to minimize transition animations:
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation-duration: 0.01ms;
}
}
This reduces animation duration for users who prefer less motion.
For more complete motion control, the application can also skip starting a View Transition when reduced motion is requested.
For example:
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
if (document.startViewTransition && !reduceMotion) {
document.startViewTransition(updatePage);
} else {
updatePage();
}
This performs the document update without starting a View Transition when reduced motion is preferred.
Browser Support
The ::view-transition pseudo-element is available in modern browsers that implement CSS View Transitions.
Same-document View Transitions are supported in current versions of major browser engines, including Chromium-based browsers, Safari, and Firefox.
Cross-document View Transitions have separate compatibility requirements and may not be available in every browser supporting same-document transitions.
To detect support for the JavaScript API:
if (document.startViewTransition) {
document.startViewTransition(updatePage);
} else {
updatePage();
}
To check whether a browser recognizes the pseudo-element selector:
@supports selector(::view-transition) {
::view-transition {
z-index: 100;
}
}
Selector support does not guarantee that a transition will be started or successfully completed.
For current compatibility information, visit Can I Use? and search for View Transitions API.
Check same-document and cross-document transition support separately when planning production features.
Specifications
The ::view-transition pseudo-element is defined in the CSS View Transitions Module Level 1 .
The specification defines the generated transition pseudo-element tree, the capture and rendering of transition images, and the mechanisms used to animate between document states.
Related features include ::view-transition-group(), ::view-transition-image-pair(), ::view-transition-old(), ::view-transition-new(), the view-transition-name property, and the @view-transition at-rule.
