CSS Animation Performance: Stick to These Properties to Avoid Jank
CSS animations can be silky smooth or frame-dropping disasters depending on which properties you animate. Learn the compositor-friendly properties and the rendering pipeline behind them.
The Rendering Pipeline
Every frame a browser renders goes through a pipeline: JavaScript, Style, Layout, Paint, Composite. Animations that trigger layout or paint stages are expensive; animations that only trigger the composite stage are cheap and run on the GPU.
The Two Properties to Animate
For virtually all animations, stick to these two CSS properties:
transform— for position, scale, rotationopacity— for fading in/out
Both are handled by the compositor thread and run on the GPU. They never trigger layout or paint.
/* GOOD: compositor-only properties */
.card {
transition: transform 200ms ease, opacity 200ms ease;
will-change: transform;
}
.card:hover {
transform: translateY(-4px) scale(1.02);
opacity: 0.9;
}
/* BAD: triggers layout on every frame */
.card-bad:hover {
top: -4px;
width: 110%;
}
Translating vs Positioning
Never animate left/top/right/bottom — always use transform: translate():
/* BAD: causes layout recalculation */
@keyframes slide-bad {
from { left: -100%; }
to { left: 0; }
}
/* GOOD: compositor only */
@keyframes slide-good {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
/* Modal entrance animation */
@keyframes modal-in {
from {
transform: scale(0.95) translateY(-10px);
opacity: 0;
}
to {
transform: scale(1) translateY(0);
opacity: 1;
}
}
will-change: Use It Carefully
will-change hints to the browser to promote an element to its own GPU layer. Speeds up animation start but costs GPU memory:
// Good: add/remove dynamically
button.addEventListener('mouseenter', () => {
target.style.willChange = 'transform';
});
target.addEventListener('transitionend', () => {
target.style.willChange = 'auto';
});
// BAD: applying will-change globally wastes GPU memory
// * { will-change: transform; } -- Never do this
Properties That Trigger Layout (Avoid in Animations)
- Dimensions:
width,height,padding,margin - Positioning:
top,left,right,bottom - Font and display:
font-size,display,border-width
Properties That Trigger Paint Only
background-color,color,border-colorbox-shadow,outline
These skip layout but still repaint. Acceptable for infrequent changes but avoid in 60fps loops.
Debugging With DevTools
Open Chrome DevTools, go to Rendering panel, and enable "Layer borders" and "Paint flashing". Green borders show GPU layers; red flashes show areas being repainted. Use the Performance panel to record and confirm no layout thrash in your animations.
Summary
The rule is simple: animate only transform and opacity. Use will-change sparingly. Check DevTools to verify your animations stay on the compositor thread. Following these rules is the difference between smooth 60fps and janky 15fps.
Admin
Cal.com
Open source scheduling — tự host booking system, thay thế Calendly. Free & privacy-first.
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!