Repaint — visual property change (color, background, visibility) without affecting layout. Less expensive.
Reflow (Layout) — geometry change (width, height, position, padding, margin). Expensive: cascades through the document.
// Layout thrashing — alternating reads and writes force reflow each iteration
for (let i = 0; i < 100; i++) {
const h = el.offsetHeight; // READ — forces layout (reflow)
el.style.height = h + 1 + 'px'; // WRITE — invalidates layout
}
// Browser must reflow 100 times! ❌
// Fix: batch all reads, then all writes
const h = el.offsetHeight; // single read
for (let i = 0; i < 100; i++) {
el.style.height = (h + i) + 'px'; // writes only
}
// Best fix: CSS transforms — composited on GPU, NO reflow
el.style.transform = 'translateY(10px)'; // skip layout entirely!
// Properties that DON'T trigger reflow (GPU composited):
// transform, opacity, filter, will-change
What triggers reflow: offsetWidth/Height, getBoundingClientRect(), scrollTop, getComputedStyle(), adding/removing DOM nodes, font changes.
💡 Use requestAnimationFrame to batch DOM reads and writes in the correct phase. Libraries like FastDOM enforce this pattern.