Interface motion · 6 min read
Motion should survive a change of mind.
Interface motion is a live relationship between states, not a prerecorded clip.
It was playing a clip
Open a menu, close it halfway, then open it again. If it snaps, queues both actions, or ignores the second click, the motion owns the interaction. The interface is showing a recording of what it expected you to do.
Useful motion does something quieter. It explains where a surface came from, keeps the relationship between old and new state, and yields immediately when intent changes.
The latest valid intent should win—even halfway through an animation.
Motion needs a cause
A menu opened by a button should feel attached to that button. A sheet should arrive from the edge that owns it. A shared element should preserve enough geometry that the eye can follow it.
transform-origin defaults to the element’s center. That default is mathematically tidy, but it can make a corner menu inflate from nowhere. Move the origin toward the trigger and the same animation suddenly explains itself.
Same movement. Only one side explains what caused it.
The latest intent wins
Reversible state usually belongs to a transition. Change the underlying property and the browser can continue from the value currently on screen—even when the destination reverses halfway.
Keyframes are not bad. They are excellent for a one-shot loader, celebration, or deliberately staged entrance. Trouble begins when separate “open” and “close” timelines are wired to a control that people can reverse at any moment.
Reverse repeatedly. The right side accepts a new destination from wherever it is now. Timing is slowed for inspection.
Less motion, same meaning
prefers-reduced-motion is not a request to remove feedback. It is a request to reduce or replace non-essential travel, zoom, parallax, and sequencing.
The content should still appear. Focus should still land correctly. The saved state still needs an icon, readable text, and a status announcement. Accessibility changes the rendering—not the contract.
Reduced motion removes travel, not confirmation.
A four-question contract
- ChangeWhat state changed, and can that be understood before anything moves?
- CauseWhich control or edge caused it, and does the spatial origin agree?
- InterruptionWhat happens when intent reverses at forty percent?
- ReductionIs the result equally clear after movement and scale are removed?
.menu {
opacity: 0;
transform: translateY(-4px) scale(.96);
transform-origin: top right;
transition: opacity 140ms linear,
transform 180ms var(--ease);
}
.menu[data-open="true"] {
opacity: 1;
transform: translateY(0) scale(1);
}
@media (prefers-reduced-motion: reduce) {
.menu {
transform: none;
transition: none;
}
}Polish is not making every change move. It is making motion trustworthy enough that users never need to think about it.
Use it as a skill
Install the motion review when an interaction needs to feel causal, interruptible, and complete without movement.
npx skills add daniasyrofi --skill interface-motion