Shots in this scene
Naming Elements and Morphing
In one line
Give an element a view-transition-name and the browser snapshots it separately and moves it from its old box to its new one. Names must be unique at the moment of capture, or the whole transition is skipped.
Think of it like this
Two train lines each have a carriage painted 7. The conductor pairs old carriage 7 with new carriage 7 and slides one into the other's place. If two carriages are both numbered 7 he cannot tell which is which, and the shuffle is called off.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- view-transition-name
- A CSS property that makes an element its own snapshot group, paired with the same name in the other state.
- group
- The pseudo-element
::view-transition-group(name)that moves from the old box to the new box. - view-transition-class
- A shared styling label, not unique, so one rule can style many groups.
- aspect ratio
- Width divided by height. Equal ratios scale into each other without squashing.
Step by step
01Without a name, everything cross-fades
Pause, press Swap (no name) and step. Only the root tracks exist (group, old and new): the old card fades out at the left while the new blue card fades in at its final spot. Two cards are visible at once.
02With a name, one card travels
Press Swap (named). group(volt), old(volt) and new(volt) tracks join the root ones, 600 ms because the CSS says so. One card moves and grows.
03Break the rule: two names the same
The second example shares one name between three cards. ready rejects with InvalidStateError and nothing animates. A unique name per card makes all three promises fulfill.
04Then change the speed
Set ::view-transition-group(volt) to animation-duration: 1500ms: the volt tracks are 1500 ms and the root tracks stay 250 ms (measured). Changing ease-in-out to linear changes group, old and new together: the pictures inherit from the group.
Try it yourself
- 1
Change the morph's duration and easing
In the first example set
::view-transition-group(volt)to 1500 ms and read the tracks: volt is 1500 ms, root stays 250 ms. Then uselinearand readgroup,oldandnew. - 2
Name only the new state
Change
#card.named { view-transition-name: volt; }to#card.big { view-transition-name: volt; }and press Swap (named): see the breakIt below.
Code & diagrams
Pause, press one button, then Step. The named version has volt tracks (600 ms, from the CSS) next to the root tracks; the unnamed one has only the root ones.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
view-transition-name: volt
view-transition-name: noneThe first flip fails with InvalidStateError but still reorders the cards. The second gives each card a unique name and animates.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Expected console output
update ran
same name on 3 cards | updateCallbackDone fulfilled | ready rejected InvalidStateError: Transition was aborted because of invalid state. Snapshot capture failed | finished fulfilled
update ran
one name per card | updateCallbackDone fulfilled | ready fulfilled | finished fulfilled
names: card-A, card-B, card-CBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Name an element in one state only
Change #card.named { view-transition-name: volt; } to #card.big { view-transition-name: volt; }.
Myth vs fact
Myth
A view-transition-name is an id: it must be unique on the whole site.
Fact
It must be unique only among elements being rendered at the moment of capture. Both pages can use volt; it need not match any id.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
A name set from script stays until you clear it: reset it when
finishedsettles if the element must not join later transitions (Topic 11.4 does this for the back/forward cache).
Remember this
- 1
The problem this solves: the default transition cross-fades the whole page, so a card that moved fades out in one place while an identical card fades in at another, and people lose track of it. A named card is tracked from its old box to its new one.
- 2
Naming.
view-transition-name: voltmakes an element its own group, cut out of the page snapshot. If the old and new states both have an element with that name, the browser animates the group from the old box to the new box while the old picture fades out and the new fades in inside it. Measured for the first example below (a 60 × 40 card that moves 120 px right and 22 px down into a 150 × 64 box): the group'stransformgoes frommatrix(1, 0, 0, 1, 6, 41)tomatrix(1, 0, 0, 1, 126, 63)(the start offset depends on what sits above the card, but the travel of 120 and 22 px is the card's own), andwidth/heightfrom60px/40pxto150px/64px. The pictures are bitmaps scaled to the group, so text goes soft mid-morph; the same aspect ratio (the Volt drawing has oneviewBoxon both pages) hardly distorts. - 3
A name must be unique when the snapshot is taken. Two elements with one name make
readyreject withInvalidStateError; the update still runs andfinishedfulfills, so the change happens with no animation. Give list items a name each (el.style.viewTransitionName = "card-" + id). - 4
Names in one state only. A name only in the old or only in the new state is no error: that group just fades out or in. A
display: noneelement's name is ignored, and when it appears only itsnewpicture exists (measured). A named element entirely off screen still gets a group and an animation (measured: x from -492 to -292), so name only what is visible. - 5
**
view-transition-class** styles many groups with one rule:view-transition-class: chipon each chip, then::view-transition-group(.chip) { animation-duration: 800ms }; names stay unique.view-transition-name: match-elementgives each element an automatic unique name (the groups are all calledmatch-elementin the timeline). In our Chromium 153 runs the class rule applied to them (three groups of 800 ms,oldpictures of 700 ms), but an earlier run left the groups at 250 ms, so name items explicitly when the timing matters.view-transition-name: autois not supported there (CSS.supportssays so).
Explain it without notes
Why does a cross-fade of a moved card confuse people, and what changes with a name?
A transition animates nothing and ready rejects with InvalidStateError. What is the likely cause, and what is view-transition-class for?
Practice
A grid of 12 cards reorders when sorted. Name each card from data-id and give every group a 400 ms ease.
Make a home-page image morph into the detail page's image without ever naming two elements hero on one page.
Done when you can
You can make one element morph between two states
You can recognise and fix the duplicate-name failure
You can use a class to style many groups at once