Shots in this scene
Composition, Play State and Events
In one line
animation-composition decides how an animation combines with the element's own value and with other animations. animation-play-state pauses it. Four events report its life, including animationcancel when it is cut short.
Think of it like this
Two people steering one shopping trolley. If both steer, the trolley follows the one who pushes last (replace), or the pushes can be added together (add). Composition is that rule. A pause button is play state. The events are the trolley's logbook: started, lap done, finished, or taken away halfway.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- composition
- How an animation's values combine with the element's own value and with other animations: replace, add or accumulate.
- underlying value
- The value the element would have with no animation, or with the lower-priority animations applied.
- play state
runningorpaused.- animationcancel
- The event that fires when an animation is removed before it finishes.
- reflow (forced)
- Making the browser work out styles and layout now, for example by reading
offsetWidth.
Step by step
01Three rules, three ends
Replay the first example, pause and step to the end: A (replace) is at 40 px, B (add) at 90 px, C (accumulate) at 70 px. Same keyframes, same starting transform.
02Read the events
The second example runs five cases and logs every event. A finished animation gives animationstart, animationend. Removing the class mid-way gives animationstart, animationcancel and no end.
Remove-then-add with no forced update gives one start and one end. With offsetWidth in between, it gives start, cancel, start, end.
03Pause and resume
In the third example the offers scroll. Hover or focus the text, or press Pause: the animation's playState becomes paused, and the console says so. Resume continues from where it stopped.
04Restart it
Read offsetWidth between removing and adding the class.
Try it yourself
- 1
Play the four cases yourself
In the events example press Remove the class. The log ends with
animationcancel, notanimationend. Press Let it finish: it ends withanimationend. Press Remove, then add and nothing restarts. Press Restart it and you get a second start. - 2
Make add and accumulate disagree
In the composition example change the element's own
transformtotranslateX(30px)only and the keyframes toto { transform: translateX(40px); }. Add and accumulate now agree (70 px), because with one function the two rules give the same sum. They only differ when the functions have scale or rotation.
Code & diagrams
Every box has its own transform. Step to the end and read the final positions: 40, 90 and 70 px.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.The cases run one after another at load (about six seconds). The buttons run one case each, and the page logs the last five events.
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
finish
animationstart
animationend
remove the class
animationstart
animationcancel
remove and add
animationstart
animationend
remove, force style, add
animationstart
animationcancel
animationstart
animationend
display none
animationstart
animationcancel
animationstart
animationendPress Pause and the console adds `after the button: paused`. Switch on Reduced motion and the text stops moving and wraps instead.
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
at load: runningBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Clean up on animationend only
In a page that removes an element on animationend, remove the class instead (as the "Remove the class" button does).
Break #2
Two animations on transform
On any box add animation: spin 1s linear forwards, drift 1s linear forwards; with @keyframes spin { to { transform: rotate(90deg); } } and @keyframes drift { to { transform: translateX(100px); } }.
Myth vs fact
Myth
animationend always fires.
Fact
Not when the animation is cancelled: removing the class, changing animation-name or hiding the element gives animationcancel instead.
Myth
Removing and re-adding a class restarts the animation.
Fact
Only if the browser sees the removal first, for example after reading offsetWidth. Otherwise nothing changes.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
animationendandanimationcancelbubble, so one listener on a parent handles children's animations. Checkevent.targetwhen you only want the parent's. - ▸
display: nonecancels, and re-showing restarts an animation whose class is still on. That can replay an entrance every time a tab panel is shown. Useanimation-fill-modeand a class set once, or anIntersectionObserver, when you do not want it.
Remember this
- 1
The problem this solves: two animations that both move
transformnormally overwrite each other, and an animation's end value ignores what the element already has. You need to combine them on purpose, and you need to know when an animation is over (to clean up) or was cut off. - 2
Composition.
animation-composition: replace(default): the animation's value replaces the element's.add: it is combined with the underlying value as a further step.accumulate: the values are summed, function by function. The first example gives each boxtransform: translateX(30px) scale(1.5)and animates totranslateX(40px) scale(2). The end values: replace is at 40 px, scale 2. Add istranslateX(30px) scale(1.5) translateX(40px) scale(2): 90 px, scale 3. Accumulate is 70 px, scale 2.5. - 3
Fighting animations. Two animations on the same property overwrite each other: the later one wins.
spin(rotate 90°) anddrift(translateX(100px)) ontransformend astranslateX(100px)only: the rotation is gone. Setanimation-composition: replace, addand they end together (a 90° turn and then 100 px along the turned axis,matrix(0, 1, -1, 0, 0, 100)). Or give each its own property:rotateandtranslate. - 4
Play state.
animation-play-state: pausedfreezes the animation where it is, andrunningcontinues from there, with no restart. It is how you make text that scrolls stop on hover or focus, or let a user pause. Anything that moves on its own for more than 5 seconds needs a way to pause (WCAG 2.2.2), and the example has one. - 5
Events.
animationstartfires when it begins (after any delay).animationiterationfires at the end of each repeat except the last.animationendfires when it finishes.animationcancelfires when it is removed before finishing: the class is removed,animation-namechanges, the element getsdisplay: none. **A cancelled animation fires noanimationend.** Each event hasanimationNameandelapsedTime, and they bubble from children. - 6
Restarting. Removing and adding the class in one go does nothing: the browser never saw it removed, so the animation just continues (one
animationstart, oneanimationend). Readingelement.offsetWidthbetween them forces the style update, so the first animation is cancelled and a new one starts. Hiding the element (display: none) cancels the animation, and showing it again starts it afresh if the class is still there.
Explain it without notes
Name the three values of animation-composition and say what each does.
Which event do you get when an animation's class is removed halfway, and why does that matter for cleanup?
How do you pause an animation without restarting it afterwards?
Practice
A card has a hover scale(1.05) animation and an entrance slide. Both use transform. Make them work together without conflicts.
Write a listener that removes an element after its exit animation, even if the animation is cancelled.
Done when you can
You can say how replace, add and accumulate combine values
You know which events each way of stopping an animation fires
You can restart an animation and know why
offsetWidthis neededYou can pause and resume without a restart, and give users a pause control