Shots in this scene
Reversing and Interrupting
In one line
When a change arrives while a transition is running, the browser starts the new transition from the value on screen. If the change goes back to where it started, the new transition is shortened so the element does not take longer to return than it took to leave.
Think of it like this
You are walking to a shop and half-way there you remember something and turn back. You do not teleport to the start, and you do not walk the whole distance again at the start. You turn around where you are and walk back the part you covered. A reversed transition does exactly that.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- reversing shortening factor
- The scaling the browser applies to the duration of a transition that returns to its start value, based on how far the first transition had got.
- interrupt
- A change that arrives while a transition is still running.
- current value
- The value the property has on screen now. A new transition starts from it.
- (hover: hover)
- A media query that is true when the main input can hover, such as a mouse and false on most touch screens.
Step by step
01Reverse at the start, the middle and the end
In "Interrupt a move" slow to 0.25×, press Go, and press Back early. The new track is short, because the box has hardly moved. Try again and press Back late: the track is nearly the full length.
02Read the new duration
Click the new track. With ease and a 1000 ms move, pressing Back at 200 ms gives a track of about 295 ms. Pressing at 800 ms gives about 976 ms.
03Retarget instead of reversing
Press Go, then Elsewhere at 200 ms. The box turns smoothly towards 100 px and the new track is the full 1000 ms.
04Sweep the strip
In "Fast toggles" move the pointer across the cells. Each one starts its own track and reverses it when you leave. Read the console for what several toggles in one frame do.
05Park the pointer
In "The doom flicker" place the pointer on the lower edge of the Bad card and keep it still. The count under it climbs without you moving. Do the same on Good: it stays at 1.
Try it yourself
- 1
Reverse at 200 ms and at 800 ms
In "Interrupt a move" use 0.25× and the pause button to press Go and then Back about 200 ms into the move. The new
transformtrack reads about 295 ms. Repeat at 800 ms: about 976 ms. Then changeeasetolinearand reverse at 400 ms: about 399 ms, the same as the elapsed time. - 2
Retarget half way
Press Go, then Elsewhere at about 200 ms. The box was at about 59 px and keeps moving smoothly towards 100 px. The track is 1000 ms again, so the last part is slow. About 700 ms after the retarget it is at 97.5 px of 100.
Code & diagrams
A 1000 ms ease move. Go, Back and Elsewhere can be pressed at any time. Use the timeline to pause and read each new track's duration.
Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.
Console
Nothing logged yet.Nine hover cells, and an audit of how many tracks N toggles in one frame make. Sweep the pointer over the cells to see reversing in action.
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
1 toggle(s) in one frame: 2 track(s)
2 toggle(s) in one frame: 0 track(s)
3 toggle(s) in one frame: 2 track(s)
6 toggle(s) in one frame: 0 track(s)Both cards lift 30 px on hover. The Bad card lifts itself, so its hit area leaves the pointer. The Good card lifts a child inside a wrapper that stays put. The counts show enter and leave 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.Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Hover that moves the thing you hover
In "The doom flicker", use the Bad card: .bad:hover { transform: translateY(-30px); }.
Myth vs fact
Myth
Hovering out always takes as long as hovering in.
Fact
A reversed transition is shortened to the distance already covered, so an early hover-out returns quickly.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
A shortened duration is visible on the track: a track that reads about 295 ms when the CSS says 1000 ms is the sign of a reversed transition. Look for it when a hover-out seems to take the wrong time.
- ▸
A transition that is interrupted is cancelled, which dispatches
transitioncancel(Topic 3.5), then a new one is run. Code that listens fortransitionendto finish an exit will never hear it for a transition that was reversed.
Remember this
- 1
The problem this solves: users do not wait for animations. They hover and leave, press and press again, open and close. If every interruption jumped to the end or restarted from the beginning, the interface would twitch. The browser's rules make interruptions smooth without any code from you, provided you know them.
- 2
The new transition starts from the value on screen. When the target changes mid-way, the old transition is cancelled and the new one starts from the property's current computed value, not from its old start or its old end. Measured with a 1000 ms
easemove to 200 px, retargeted to 100 px at 200 ms: the box was at 59.05 px and the new 1000 ms transition began from 59.05 px, with no jump. - 3
Reversing is shortened. If the new target is the value the old transition started from (it is going back), the browser applies a reversing shortening factor: the new duration is scaled by how far the old transition had got, measured on the eased progress and not on time. With a linear curve, reversing at 400 ms of 1000 ms gave a 399 ms transition. With
ease, reversing at 200 ms gave about 295 ms, becauseeasehad already covered about 29% of the distance. Reversing at 800 ms gave about 976 ms, sinceeaseis nearly done by then. - 4
Only the exact return reverses. If the new target is a different value (
100pxinstead of the start), it is a new transition with the full duration, measured from the current value. The distance is shorter, so it feels slower per pixel. That is how the third button in the first example behaves. - 5
Several changes in one frame count as one. The browser compares the style at the end of a frame with the style at the end of the last one. Toggling a class twice in the same script is no change; three times is one change. In the audit below, one toggle made two tracks, two toggles made none, three made two, six none. This matters for code that flips a state quickly and expects each flip to show.
- 6
The doom flicker. If hovering an element moves it, the pointer can end up outside it. The hover ends, the element moves back, the pointer is over it again, and the loop runs. With the pointer parked 3 px above the lower edge of a card 32 px high that lifted 30 px on hover, Chromium reported about 80 enter and leave events in about 1.6 seconds without the mouse moving (measured). A lift of 4 px did not flicker: the pointer stayed inside the card. Put the hover on a wrapper that does not move, and move the child. The wrapper's hit area stays under the pointer (one enter event, in the same test).
- 7
Touch devices have no hover. On a phone a tap sets
:hoverand it can stick after the finger lifts. Wrap hover-only styling in@media (hover: hover), so touch users never see a half-applied hover. In a touch-emulated browser the media query answered false (measured), and the hover rules did not apply. The press (:active) is the touch feedback (Topic 3.6).
Explain it without notes
A user hovers a card for 100 ms of a 400 ms transition and leaves. How long does the return take, and why?
Why can a card that lifts on hover flicker, and what is the fix?
What does @media (hover: hover) protect against?
Practice
Make a card that lifts 6 px on hover without flicker, using a wrapper.
A menu opens with a 300 ms transition and closes with the same one. A user clicks open, then close at 100 ms. Describe what the browser does with the closing transition.
Done when you can
You can say where a new transition starts when it interrupts another
You can explain the reversing shortening factor with a number
You can find and fix a hover that moves away from the pointer
You wrap hover-only styling in a (hover: hover) query