Principles
The ten rules every buttery animation follows, and the few things it never animates.
buttery's motion follows ten rules, measured from apps that feel smooth to use. Use them to decide whether something should move at all, and how, before reaching for a preset.
The ten rules
Direct manipulation is instant
Dragging a slider or picking a swatch updates the result in the same frame. A value the person is driving is set, never tweened.
Discrete changes settle in about 250ms
A change of state settles with no overshoot, on
spring.smooth. Small selection indicators, such as a segmented control's pill, are quicker, onspring.snappy.One surface morphs
A surface changes shape instead of closing and reopening: a menu that switches sections resizes, and a card that opens becomes its dialog.
Containers follow their content
A container animates its height when what's inside it changes, and the content crossfades.
New context dims
Rather than blacking out, a menu over content blurs the page behind, and a dialog darkens it.
Arrivals are choreographed
A hero or a grid enters with a short rise and fade, staggered about 50ms, in 900ms at most, once.
Exits are faster than entrances
An exit takes about 60% as long as its entrance, because the person has already decided.
Hover answers within 150ms
An arrow extends, a card lifts 2px. Nothing is shown only on hover.
Celebrations are rare
Confetti fires only for a real finish, such as completing onboarding.
Reduced motion is a mode of its own
Springs become instant, reveals become plain fades of 100ms at most, loops stop and confetti is off. Layout still updates.
What never animates
- Numbers a person typed or set.
- Layout during a drag.
- Anything longer than 400ms, apart from choreographed entrances and ambient loops.
CSS transitions
CSS transitions move only opacity, transforms, colors, shadows, filter and backdrop-filter. A change of size or position goes through Motion's layout.
.chip {
transition: background-color var(--bt-dur-fast) var(--bt-ease-out);
}Transition the property that changes, on a token.
.chip {
transition: all 120ms;
}transition: all animates layout too, and buttery's stylelint config fails it.