By Rahul — Google Frontend Engineer
What is Reflow (Layout)?
Reflow calculates the position and size of every element. It is expensive because changing one element can affect its siblings, children, and parents. Also called "layout" in Chrome DevTools.
What Triggers Reflow
// These all trigger reflow:
element.style.width = '200px';
element.style.height = '100px';
element.style.padding = '10px';
element.style.margin = '20px';
element.style.display = 'block';
element.style.position = 'absolute';
element.style.fontSize = '16px';
element.classList.add('wider');
window.resize event;
element.offsetHeight; // READING layout also triggers reflow!What is Repaint?
Repaint updates visual properties without changing layout. Cheaper than reflow.
// These trigger repaint only (no reflow):
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.visibility = 'hidden'; // NOT display:none (that is reflow)
element.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)';The Composite-Only Properties
// These skip BOTH reflow and repaint:
element.style.transform = 'translateX(100px)';
element.style.opacity = '0.5';
// They run on the GPU compositor thread
// This is why transform animations are smooth and width animations are notLayout Thrashing (The Performance Killer)
// BAD — forces layout on every iteration
const items = document.querySelectorAll('.item');
items.forEach(item => {
const height = item.offsetHeight; // READ → forces layout
item.style.height = height * 2 + 'px'; // WRITE → invalidates layout
// Next iteration: READ forces layout again!
});
// GOOD — batch reads, then batch writes
const heights = Array.from(items).map(item => item.offsetHeight); // All reads
items.forEach((item, i) => {
item.style.height = heights[i] * 2 + 'px'; // All writes
});Use requestAnimationFrame
// GOOD — schedule DOM writes for the next frame
function updateLayout() {
requestAnimationFrame(() => {
elements.forEach(el => {
el.style.transform = `translateY(${newPosition}px)`;
});
});
}Best Practices
- Animate
transformandopacityonly — they skip layout and paint - Batch DOM reads and writes — never interleave them
- Use
will-change: transformto promote elements to their own layer - Use CSS
contain: layoutto isolate reflow scope - Use Chrome DevTools Performance tab to identify forced reflows
Summary
Reflow recalculates layout (expensive). Repaint updates visual properties (moderate). Transform/opacity skip both (cheap). Avoid layout thrashing by batching reads and writes. Use transform for animations.