Catalog / Technique
View transition
Use when a navigation, an opening or a reordering should be a movement and not a cut: a picture that travels from a listing to its page and back, a thumbnail that opens in place, rows that move when a list is sorted. Covers cross-document and same-document view transitions, naming at navigation time, the aspect rule, the language switch, one arrival per page, the head script, and how a transition is looked at.
- Loads as
technique-view-transition- Written for
- An agent, to follow
View transition
The browser photographs the page before a change, lets the page after it stand above, and animates between the two. An element named in both states morphs from its old box to its new one. Across two documents it is switched on by one at-rule in each; within one document it is a call around the change. Nothing is drawn by script: the pseudo-element tree is the browser’s, and the recipe’s whole job is to say what is named, when, and how the page moves.
When to use
- A listing whose rows lead to pages: the picture and the title travel to the hero, and back. Once per navigation, over content that is already readable.
- A gallery whose thumbnails open into the picture, in place, with the browser’s own focus trap and back button.
- A list that is sorted or filtered while the reader watches.
- A language switch, which is the bilingual site’s most repeated navigation and the one where the reader most needs to stay where they were.
Do not use it for:
- A reload, a typed address, or a navigation from another origin. The browser runs no transition for those, by design.
- Text that changes language. Two headings cross-fading inside one tweening box are two words on top of each other.
- A table of data. A row that travels is a row the reader loses their place in.
- A page whose body depends on module or linked scripts running on arrival, in Firefox: the swap there runs a new body’s inline scripts only.
Rules
- Name few things, at navigation time, and clear them after. A
duplicate
view-transition-namein one document cancels the whole transition. A name set inpageswaporpagerevealfor the one navigation, and removed onfinishedand onpageshow, cannot clash: a project listed twice travels from whichever row was clicked. - The head script is classic and blocking.
pagerevealfires before the arriving document’s first render; a module script comes after it. Measured 2026-10-09 in Chrome 155: a blocking head script that appends@view-transition { navigation: auto }itself opts the document in. No stylesheet fragment is needed. - What travels is said in the markup, not in a selector.
data-morph="plate"anddata-morph="title", inside each link on a listing and standing alone on the page it leads to. - Morphing pictures:
height: 100%,object-fit, andoverflow: clipon both snapshots. Without the clip both overflow the box mid-flight. The cure that removes the problem is one ratio at both ends. - A named ancestor flattens its named descendants. Restate the
stacking with
z-indexon the groups: the plate above the root, the title above the plate, anything that must stay on top with a name of its own, a canvas included. - Never morph text between two languages. A language switch keeps
the reader’s place instead: the first heading on screen and its
distance from the top, saved on the leaving page, restored before
the twin’s first render; the old text out quickly, the new in after.
Recognise the twin from the page’s own
link rel="alternate" hreflangelements, never from the shape of the path. - Keeping the place must not depend on the transition. Save it on the link’s click, restore it from the head script; a browser with no transitions restores it after its first render, as a jump.
- Do not depend on
navigation.activation. Take the destination from the clicked link andpageswap’s ownactivationwhere it exists; write the record tosessionStorageand read it on the other side. - One arrival per page. A page entered by transition stamps
data-arrival="transition"onhtmland never removes it; a load effect reads that and does not play a second arrival. - What skips a transition is a slow first render, not a slow server. The four-second limit runs from the capture of the old page to the first render of the new. Do not hold render to wait for content without measuring.
- Reduced motion is decided in script, once. Skip the transition
in both events, or add a type under which nothing travels and the
root cross-fades. The at-rule is never nested in a media query,
which a host’s
matchMediaoverride cannot see. - Same-document: decode before you show. The picture is decoded inside the callback so the new state is never an empty box; the page is frozen while the callback runs.
- A change asked for mid-flight waits. Starting a second transition while one runs skips one of them and leaves a name behind. Keep the request and run it when the first lands.
match-elementis for one document only, and it is the whole engine of a reflow: a name the browser derives from the element cannot clash and costs nothing to assign. It cannot be addressed one row at a time, so there is no stagger.- Chromium-only features are enhancements by feature test, never foundations: nested groups, element-scoped transitions, generated carousel controls.
- Where only same-document transitions exist (Firefox), swap the
page in. Fetch the next document and, inside one transition,
replace the body, set the title and the language, push the address,
run the new body’s inline scripts. Back and forward swap the same
way; a page that cannot be fetched is the browser’s. The same names,
types and movements serve both engines. The feature test is the
PageRevealEventconstructor. Seetechnique-compatibility.
Decisions
| Question | Choose | Because |
|---|---|---|
| A second recipe shape for page transitions? | No: the same shape, called from the head | The only thing that differs is when mount is called; the head script can opt the document in itself (measured) |
| Name shared elements in CSS or at navigation time? | At navigation time | Fixes the project listed twice and keeps captures to what moves |
| The page’s own movement? | A choice: fade, slide, iris from the click, wipe | A taste; back is the same movement reversed |
| Aspect strategy for a picture that changes shape? | Cross-fade under cover, with the clip; a choice | The research’s table; one ratio at both ends is a layout decision |
| Does the title travel? | A toggle, on | A taste |
| Language switch? | Hold: no travel, the old out quickly, the new in after; keep the place | Two languages never both legible; the reader stays where they were |
| Reduced motion? | None, or a fade; a choice, none by default | Chrome’s guide argues for a fade; it is a matter of taste |
| A load effect on a page entered by transition? | Skip, stamped | Playing it costs a second arrival on every internal navigation |
| Gallery opening? | Both: navigate is page-morph on a card, in place is gallery-open |
Different products; the second brings the dialog’s focus handling |
| How is it looked at? | The stage’s hold: 25, 50 or 75 percent of the run, through pausing the pseudo-element animations after ready |
A 300 ms movement cannot be judged in flight; a held frame can be read by a check too |
Tuning
| Dial | Start | Range | One end | The other |
|---|---|---|---|---|
| Page duration (ms) | 320 | 220 to 450 | A cut with a flash | Waited out |
| Plate factor | 1.15 | 1 to 1.4 | The picture lands with the page | The picture is still arriving when the page has |
| Opening duration (ms) | 360 | 240 to 420 | A pop | A slow zoom |
| Reflow duration (ms) | 320 | 200 to 500 | Rows jump | Rows drift |
| Backdrop | 0.82 | 0.6 to 0.95 | The page shows through | A black room |
Ranges are estimates; the first consumer runs its page at 384 ms and its plate at 1.15 times that.
Rest state
A plain navigation, a link that opens the picture, a list that simply changes. The same without the feature, under reduced motion (by default), on a reload, and in Firefox across documents. No recipe here hides, moves or re-parents content it did not create.
Cost
- To build: small each; the head recipe is medium, most of it the record between two documents and the four movements.
- To run: no script per frame; each named element is a texture for
its old state and a live layer for its new one. Naming at navigation
time keeps it to the two that travel. The browser’s default
transition took 250 to 300 ms from
pagerevealtofinishedon a fast local server. Sizes:page-morphabout 3 kB gzipped,gallery-openabout 2.2,listing-reflowabout 1.3. - To the reader: a navigation that is answered rather than cut, at the price of a third of a second during which input may not land. Keep it under about 400 ms.
Checklist
- The budget check passes.
-
npm run check:browser: forward, held at 50 percent, the plate group is paused between the card and the hero; released, no name remains. -
npm run check:browser: back names the row that was clicked, not the first of a duplicate pair; a reload runs no transition. -
npm run check:browser: the Turkish twin opens with the same heading the same distance down. -
npm run check:browser: under reduced motion a click navigates with no transition. -
npm run check:browser: the dialog opens with the picture named and the thumbnail untouched; Escape mid-flight ends closed with nothing named; back closes it. -
npm run check:browser: rows reorder as themselves and hidden rows are never removed. - Looked at on the stage with the hold at each stop, once per movement, and once at phone size.
- Run once in Safari and once in Firefox before it is marked passed.
Recipes
page-morph: a picture and its title travel between two documents; the page fades, slides, irises or wipes; a language switch keeps the place.gallery-open: a thumbnail opens into the picture in place, and back.listing-reflow: rows travel to their new places when a list is sorted or filtered.
Sources
chrome-vt-cross-document: the at-rule, the two events, the four-second limit, what navigations qualifychrome-vt-same-document: the same-document call and the aspect recipecsswg-view-transitions-1: an element is captured as painted; the pseudo-element tree is outside the accessibility treechrome-element-scoped-vt: element-scoped transitions, Chromium onlychrome-nested-vt-groups: what the flat tree loses, and that unsupported browsers ignore the propertychrome-view-transitions-2025:match-elementworks within one document onlybcd-view-transition-at-rule: support for cross-document transitionswebdev-vt-baseline: same-document transitions in every enginebcd-files-2026-10-06: the conflicting Safari dates foractivation, which is why nothing depends on itnng-animation-duration: where a transition starts to read as delayroselli-dont-split-words: why text is never split or morphed letter by letter