CSS References
CSS Animatable Properties
Not every CSS property can be animated, and among those that can, some are far cheaper for the browser to render than others. A property is animatable if the browser can compute smooth intermediate values between two states. This reference lists commonly animated properties and, crucially, explains which ones are performant.
Performance first: prefer transform and opacity
Rendering a frame goes through layout, paint and composite. Animating a property that changes geometry (width, top, margin) forces layout on every frame, which is expensive. transform and opacity can be handled entirely on the compositor, often on the GPU, so they stay smooth even on low-end devices.
Rule of thumb: to move, size or fade something, use transform: translate()/scale() and opacity instead of top/left/width/height. Add will-change: transform sparingly for heavy animations.
Cheap to animate (composite only)
| Property | Notes |
|---|---|
| transform | translate, scale, rotate, skew — GPU-friendly, no layout. |
| opacity | Fades in/out on the compositor — very cheap. |
| filter | blur, brightness, etc. — GPU, but heavy blurs can cost. |
Animatable but triggers paint or layout
| Property | Cost | Notes |
|---|---|---|
| color | Paint | Interpolates between colours smoothly. |
| background-color | Paint | Smooth colour transition. |
| border-color | Paint | Animates fine. |
| box-shadow | Paint | Animatable but repaints; can be costly. |
| background-position | Paint | Used for subtle motion effects. |
| width / height | Layout | Reflows the page each frame — avoid if possible. |
| margin / padding | Layout | Triggers layout; prefer transform. |
| top / right / bottom / left | Layout | Triggers layout; use translate instead. |
| font-size | Layout | Reflows text; expensive. |
| line-height | Layout | Reflows; expensive. |
| border-width | Layout | Changes box size; triggers layout. |
| flex-grow / flex-basis | Layout | Animatable; reflows the flex container. |
Discrete (not smoothly interpolated)
Some properties change abruptly at the halfway point rather than sliding through in-between values.
| Property | Behaviour |
|---|---|
| display | Historically jumped; @keyframes can now interpolate to/from none with allow-discrete. |
| visibility | Switches at 50% unless paired with an easing trick. |
| position | Not interpolated — changes instantly. |
| font-family | Not animatable — swaps instantly. |
A smooth, performant example
<!DOCTYPE html>
<html>
<head>
<style>
.card {
transition: transform 200ms ease, opacity 200ms ease;
}
.card:hover {
transform: translateY(-6px) scale(1.02);
opacity: 0.95;
}
</style>
</head>
<body>
<div class="card" style="padding:24px;background:#0f766e;color:#fff;border-radius:12px;width:200px;">
Hover me — animated with transform and opacity only.
</div>
</body>
</html>Respect users who set prefers-reduced-motion by wrapping non-essential animation in @media (prefers-reduced-motion: no-preference).
