Trình duyệt biến các thay đổi CSS thành pixel qua một pipeline, và các thay đổi khác nhau kích hoạt các giai đoạn khác nhau (tốn kém ít hay nhiều):
Style → Layout (reflow) → Paint → Composite
Trình duyệt biến các thay đổi CSS thành pixel qua một pipeline, và các thay đổi khác nhau kích hoạt các giai đoạn khác nhau (tốn kém ít hay nhiều):
Style → Layout (reflow) → Paint → Composite
/* ❌ kích hoạt LAYOUT (reflow) — tốn kém, tính lại hình học mỗi frame */
width, height, top, left, margin, padding, font-size
/* ⚠️ kích hoạt PAINT — tô lại pixel */
color, background, box-shadow, border-radius
/* ✅ chỉ kích hoạt COMPOSITE — GPU, không layout/paint */
transform, opacity
Đây là quy tắc hiệu năng quan trọng nhất: animate transform và opacity, không phải width/top/margin. Animate các thuộc tính layout sẽ chạy lại layout ở mỗi frame (giật); transform được composited bởi GPU (mượt 60fps).
/* ❌ giật */ @keyframes a { to { left: 300px; width: 200px; } }
/* ✅ mượt */ @keyframes b { to { transform: translateX(300px) scaleX(2); } }
.animated { will-change: transform; } /* nâng lên thành một lớp GPU riêng trước */
Dùng will-change chỉ trên các phần tử sắp animate — lạm dụng nó lãng phí bộ nhớ do tạo quá nhiều lớp.
// ❌ đọc-ghi-đọc-ghi buộc nhiều lần reflow đồng bộ
for (const el of els) { el.style.width = el.offsetWidth + 10 + "px"; }
// ✅ gom các lần đọc, rồi ghi
const widths = els.map(el => el.offsetWidth);
els.forEach((el, i) => el.style.width = widths[i] + 10 + "px");
- contain: layout/paint — cô lập một nhánh con để thay đổi không reflow cả trang
- content-visibility: auto — bỏ qua render nội dung ngoài màn hình
- giảm thiểu selector lồng sâu và các stylesheet thừa lớn
Hiệu năng render chủ yếu là về việc không kích hoạt layout nhiều lần.
Biết rằng transform/opacity chỉ composite (rẻ) trong khi width/top/margin ép reflow (đắt) — cùng với việc tránh layout thrashing và dùng contain/content-visibility — là điều giữ animation ở 60fps và trang cảm thấy nhanh.