CSS Animations & Transitions
debt(d5/e3/b3/t5)
Closest to 'specialist tool catches' (d5). Lighthouse and Chrome DevTools (from detection_hints.tools) can identify layout thrashing and animation performance issues through Performance panel recordings and Lighthouse audits, but these require deliberate profiling — the jank isn't caught by default linters or build-time checks.
Closest to 'simple parameterised fix' (e3). The quick_fix shows a pattern replacement: swap width/height animations for transform: scale(), swap left/top for transform: translate(). This is a targeted refactor within CSS files, not a single-line fix but also not cross-cutting architectural work.
Closest to 'localised tax' (b3). Animation choices affect specific components' CSS rather than the entire codebase. Poor animation patterns cause local performance issues but don't impose system-wide constraints — you can fix one component's animations without touching others. The reach is limited to frontend presentation layer.
Closest to 'notable trap' (t5). The misconception states developers believe 'all CSS animations are hardware-accelerated' when only transform and opacity use GPU compositing. This is a documented gotcha that most frontend developers eventually learn through performance debugging, but it's not immediately obvious from CSS syntax that animating 'width' behaves fundamentally differently from animating 'transform'.
Also Known As
TL;DR
Explanation
CSS transitions: transition: property duration easing — animate between two states on event. Keyframe animations: @keyframes + animation property — define multi-step sequences that play automatically. For performance, only animate properties that the browser can composite on the GPU without triggering layout: transform (translate, scale, rotate) and opacity. Animating width, height, top, left, or color triggers layout/paint, causing jank. Use will-change: transform as a hint for complex animations. prefers-reduced-motion media query should disable or reduce animations for users who request it.
Diagram
flowchart LR
subgraph GPU Composited - Smooth 60fps
T[transform: translate scale rotate]
O[opacity]
T & O --> GPU[GPU thread<br/>no layout recalc]
end
subgraph CPU - Causes Jank
W[width height top left]
BG[background-color]
W & BG --> CPU[Main thread<br/>layout + paint every frame]
end
style GPU fill:#238636,color:#fff
style CPU fill:#f85149,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Animating width/height for expand effects — use transform: scaleY() instead.
- Animating left/top for movement — use transform: translateX/Y() instead.
- Not respecting prefers-reduced-motion — vestibular disorders make animations cause physical discomfort.
- will-change on every element — hints consume GPU memory; use only on elements with complex animations.
Code Examples
/* Janky — triggers layout on every frame:
.box {
transition: width 0.3s, left 0.3s; /* Layout properties — CPU bound */
}
.box:hover {
width: 200px; /* Forces layout recalculation */
left: 100px; /* Forces layout recalculation */
}
/* Smooth — GPU composited:
.box {
transition: transform 0.3s ease, opacity 0.3s ease;
will-change: transform; /* Hint for complex cases only */
}
.box:hover {
transform: translateX(100px) scaleX(1.5); /* GPU only, no layout */
}
/* Respect reduced motion:
@media (prefers-reduced-motion: reduce) {
.box { transition: none; }
}