Single Page Applications (SPAs) provide the appearance of navigation by replacing the content of the page without navigating to a new page. By default, the content is simply replaced, without any transitions. Directional transitions can visually reinforce a spatial relationship between views.
By sliding new content in from the direction the user is moving you create a mental map of the application structure. For instance, a product site may show a transition to the right for "forward," and to the left for "back", or a slideshow may transition up and down to show next and previous slides.
Implementation Steps
- Detect Navigation Direction: Determine if the user is moving "forward" or "backward" in the application flow. How you detect the direction depends on your use case.
- Trigger Transition with Types: Pass the direction in a
typesarray todocument.startViewTransition()to categorize the transition. - Define Directional Animations with CSS: Use the
:active-view-transition-type()pseudo-class to apply specific animations based on the navigation type.
Defining Keyframes
Define sliding animations to and from each direction. For best performance, animate position changes using the transform property or the individual transform properties, scale, rotate, and translate. opacity is generally performant as well, but avoid animating other CSS properties without first verifying that they don't trigger layout or painting.
/* Slide an element out to the left */
@keyframes slide-to-left {
/* Mandatory: animate `transform` instead of inset properties for better performance. */
to { transform: translateX(-100%); }
}
/* Slide an element in from the right */
@keyframes slide-from-right {
from { transform: translateX(100%); }
}
/* Slide an element out to the right */
@keyframes slide-to-right {
to { transform: translateX(100%); }
}
/* Slide an element in from the left */
@keyframes slide-from-left {
from { transform: translateX(-100%); }
}
Set up shared animation settings
Use the ::view-transition-group(root) selector to apply animation settings that are shared across all transitions.
::view-transition-group(root){
animation: 0.4s ease-in-out both;
}
Applying Directional Animations
Use the active-view-transition-type pseudo-class to target the transition views specifically when the "forward" or "backward" type is active.
/* MANDATORY: Apply forward animations when the 'forward' type is active */
html:active-view-transition-type(forward)::view-transition-old(root) {
animation-name: slide-to-left;
}
html:active-view-transition-type(forward)::view-transition-new(root) {
animation-name: slide-from-right;
}
/* MANDATORY: Apply backward animations when the 'backward' type is active */
html:active-view-transition-type(backward)::view-transition-old(root) {
animation-name: slide-to-right;
}
html:active-view-transition-type(backward)::view-transition-new(root) {
animation-name: slide-from-left;
}
Triggering the Transition
When navigating, pass the appropriate type to the startViewTransition method.
const transitionType = yourTransitionTypeLogic();
const updateDOM = yourUpdateDOMLogic();
document.startViewTransition({
update: updateDOM,
types: [transitionType] // Matches the CSS :active-view-transition-type() selectors
});
Accessibility
Always respect user preferences for reduced motion by disabling or simplifying animations.
@media (prefers-reduced-motion: reduce) {
::view-transition-group(root) {
animation: none !important;
}
}
Fallback strategies
The View Transitions API is a progressive enhancement. In unsupported browsers, document.startViewTransition will be undefined. You must wrap your navigation logic in a feature detection check to ensure the DOM update still occurs immediately without animation, as shown in this helper function.
/**
* Navigates to a new view with a directional transition.
* @param {Function} updateDOM - Callback to update the DOM state.
* @param {string} direction - Either 'forward' or 'backward'.
*/
function navigate(updateDOM, direction) {
// Feature detect for browsers that do not support View Transitions
if (!document.startViewTransition) {
updateDOM();
return;
}
// Start transition with the specific navigation type
document.startViewTransition({
update: updateDOM,
types: [direction] // Matches the CSS :active-view-transition-type() selectors
});
}