Page Transition Patterns
A page transition is the most expensive animation in a UI: it takes over the entire viewport for around 300–500ms. Done right, it gives the user spatial context — they know where they’re going within the app. Done wrong, it’s just a delay.
Pick a transition type above, then click the nav on the left to change pages
The purpose of a page transition
A transition isn’t there to look “pretty.” Its purpose is to:
- Confirm the action: tap a button → something happens (avoid a frozen feeling)
- Spatial context: where the new page sits relative to the old one (drill-in, go back, peer navigation)
- Mask loading: hide the time spent fetching data
If a transition doesn’t serve at least one of these three purposes, consider dropping it entirely.
Pattern 1: Fade
The simplest option, and the best fit for navigation with no spatial relationship.
@keyframes page-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.page-enter {
animation: page-fade-in 0.2s ease-out;
}
Use when: tab navigation, top-level menu items, modal-to-modal. When two pages have no parent–child or before–after relationship.
Avoid: fades that are too long (> 300ms) — users perceive them as lag, not as a transition.
Pattern 2: Slide (direction-aware)
The new page slides in from the direction that matches the action, building a spatial map in the user’s mind.
/* Drill in: new page comes from right */
.page-enter-right {
animation: slide-from-right 0.3s cubic-bezier(0.2, 0, 0, 1);
}
/* Go back: new page comes from left */
.page-enter-left {
animation: slide-from-left 0.3s cubic-bezier(0.2, 0, 0, 1);
}
@keyframes slide-from-right {
from { transform: translateX(24px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes slide-from-left {
from { transform: translateX(-24px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
Important note: don’t slide too far. translateX(24px) is enough to create a directional cue — translateX(100vw) is dizzying and far too slow.
Use when: there’s a breadcrumb hierarchy (list → detail → deeper detail), wizard/onboarding steps, or back navigation.
Pattern 3: Shared element transition
An element from the old page “becomes” an element on the new page. This creates the strongest sense of continuity.
// View Transition API (native browser, Chrome 111+)
document.startViewTransition(() => {
// Update DOM here
navigateTo(newPage);
});
/* CSS to define the shared element */
.card-image { view-transition-name: hero-image; }
.detail-image { view-transition-name: hero-image; }
The browser automatically interpolates position and size between two elements that share the same view-transition-name.
Use when: card → detail page, thumbnail → full view, product list → product page.
Fallback: if the browser doesn’t support the View Transition API, fall back to a fade.
if (document.startViewTransition) {
document.startViewTransition(() => navigateTo(newPage));
} else {
navigateTo(newPage); // instant, no transition
}
Timing guidelines
| Transition type | Duration | Easing |
|---|---|---|
| Fade | 150–200ms | ease-out |
| Slide (small offset) | 250–350ms | cubic-bezier(0.2, 0, 0, 1) |
| Slide (full page) | 300–400ms | cubic-bezier(0.2, 0, 0, 1) |
| Shared element | 350–500ms | cubic-bezier(0.2, 0, 0, 1) |
Always use ease-out (fast in, slow settle) for the entering transition. The page is “arriving” — fast in feels responsive, slow settle feels controlled.
The exit (the old page leaving) usually uses ease-in, or simply a quick fade-out (100ms).
Common mistakes
Two-directional transitions at once: the old page slides left AT THE SAME TIME the new page slides in from the right → too much motion, and the brain doesn’t know where to focus. Better: fade the old page out quickly, then slide the new page in.
Transitions that are too large on mobile: translateX(100vw) on a small screen → needs > 400ms to cross the screen → feels slow. Scale it down to 20–30% of the width.
Not disabling for prefers-reduced-motion:
@media (prefers-reduced-motion: reduce) {
.page-enter { animation: none; }
}
Further reading: Cubic Bezier in Depth, Ease vs Spring, Scroll Reveal Patterns.