Motion guides attention and makes interfaces feel alive — when done well. This lesson covers transitions, transforms and keyframe animations, plus the golden rule of performant motion that keeps everything smooth.
Transitions recap and timing
A transition animates a property between two states over time. The timing function shapes the motion: <code>ease</code>, <code>linear</code>, <code>ease-in-out</code>, or a custom <code>cubic-bezier()</code>. Good easing makes motion feel natural rather than mechanical.
<div class="box">Hover me</div>.box{width:120px;padding:24px;background:#2563eb;color:#fff;border-radius:10px;text-align:center;transition:transform .3s cubic-bezier(.16,1,.3,1),background .3s}
.box:hover{transform:translateY(-8px) scale(1.03);background:#1e3a8a}Transforms
The <code>transform</code> property moves, rotates, scales and skews elements: <code>translate()</code>, <code>rotate()</code>, <code>scale()</code>, <code>skew()</code>. Transforms do not affect layout (they do not push neighbours), which is exactly why they are fast.
| Function | Effect |
|---|---|
| translate(x, y) | Move |
| scale(n) | Resize |
| rotate(deg) | Rotate |
| skew(deg) | Slant |
Keyframe animations
For motion beyond two states, <code>@keyframes</code> defines stages from 0% to 100%, applied with the <code>animation</code> property. Great for loaders, attention pulses and entrances.
<div class="pulse">Pulsing</div>@keyframes pulse{0%,100%{transform:scale(1);opacity:1}50%{transform:scale(1.08);opacity:.7}}
.pulse{display:inline-block;padding:16px 22px;background:#0d9488;color:#fff;border-radius:10px;animation:pulse 1.6s ease-in-out infinite}The performance golden rule
Animate only <code>transform</code> and <code>opacity</code> whenever possible. These run on the GPU and do not trigger layout or paint, so they stay at 60fps. Animating <code>width</code>, <code>top</code>, <code>margin</code> or <code>height</code> forces expensive layout recalculation and causes jank.
.x:hover { margin-top: -8px; width: 110%; }.x:hover { transform: translateY(-8px) scale(1.05); }Animating layout properties like width or top, which is slow and janky. Use transform instead — it is GPU-accelerated.
Animate transform and opacity only, keep durations short (150–300ms for UI), use easing that feels natural, and always respect prefers-reduced-motion (covered next). Motion should support the UI, not distract from it.
Make a card lift and scale slightly on hover using only transform with a cubic-bezier easing. Then create a @keyframes spinner or pulse that loops infinitely.
1. Which properties are cheapest to animate?
2. What defines multi-stage animation?
3. Why avoid animating width/top?
- Transitions animate between two states; @keyframes handles many stages.
- transform moves/scales/rotates without affecting layout.
- Animate only transform and opacity for 60fps motion.
- Keep UI motion short and naturally eased.