Transitions, transforms and animation
Which properties can transition, timing functions, transform functions and 3D, keyframe animation and reduced motion.
Transitions need a state change
A transition interpolates between two values of the same property. It fires when a computed value changes, which is why it is almost always paired with a hover, focus or class toggle.
.btn {
background-color: var(--brand);
transition: background-color 150ms ease-out, transform 150ms ease-out;
}
.btn:hover { background-color: oklch(50% 0.17 258); transform: translateY(-1px); }
.panel { transition: opacity 200ms ease-out, transform 200ms ease-out; }
.panel[hidden] { opacity: 0; transform: translateY(-4px); }| Timing function | Feel |
|---|---|
linear | Mechanical β good for progress bars and spinners |
ease-out | Fast start, gentle finish β the default for entering elements |
ease-in | Slow start β for elements leaving the screen |
ease-in-out | Symmetric β for moves within the viewport |
cubic-bezier(.2,.8,.2,1) | Snappy and modern β a common UI default |
steps(4, end) | Discrete jumps β for sprite frames and counters |
- Only animatable properties transition:
transformandopacityare cheap, whilewidth,height,topandmargintrigger layout on every frame. - Property shorthand such as
backgroundtransitions inconsistently; name the exact properties instead. transition: allalso animates things you did not intend β including properties a later library changes.- A
display: nonetoggle cannot be transitioned; animate visibility and opacity, or use@starting-style.
Transforms and 3D
A transform moves, rotates or scales a box without disturbing the layout around it, and it can be composited on the GPU β which is why it is the workhorse of interface motion.
.card:hover { transform: translateY(-4px) scale(1.02); }
.spinner { animation: spin 1s linear infinite; }
.flip { transform: perspective(800px) rotateY(180deg); transform-style: preserve-3d; }
.avatar { transform: rotate(-3deg); transform-origin: center bottom; }
@keyframes spin { to { transform: rotate(360deg); } }- Functions apply right to left, so order changes the result:
translatethenrotateis not the same asrotatethentranslate. - An element with a transform becomes the containing block for its fixed descendants and creates a stacking context.
transform-originsets the pivot point; the default is the centre of the box.- 3D needs
perspectiveon the parent or in the same transform list, plustransform-style: preserve-3dfor nested faces. - Reserve
will-change: transformfor elements that animate continuously β applied everywhere it just consumes memory.
Keyframes and reduced motion
An animation runs on its own timeline from a set of keyframes, which makes it the right tool for anything that loops, plays on load, or has more than two states.
@keyframes slide-in {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
.toast {
animation: slide-in 200ms ease-out both;
animation-delay: 80ms;
}
@media (prefers-reduced-motion: reduce) {
.toast { animation: none; }
}- The
animationshorthand takes name, duration, timing, delay, iteration count and fill mode β in that loose order, with the first two time values mapped to duration then delay. bothas a fill mode keeps the final keyframe applied after the animation ends, instead of snapping back.animation-fill-mode: backwardsapplies the first keyframe during the delay, which prevents a flash of unstyled position.- Beware of looping animations that never pause: they cost battery and can prevent a laptop from suspending.
β οΈ
Motion can cause nausea and vertigo for some people. Honour
prefers-reduced-motion for anything that moves more than a few pixels, and prefer a short opacity fade over a large translation when motion is reduced.FAQ
Why does my transition not run?
Either the property is not animatable, the value change happens on an element that was just created, or the change comes from a
display toggle. Animate opacity and transform on an element that already exists.Transition or animation?
A transition needs a trigger and interpolates between two states. An animation runs on its own, can loop, and can define several intermediate states. Reach for the simpler one that fits.
Related
Positioning, stacking and overflow Debugging CSS, resets and browser support
Last refreshed 2026-09-18.