Performanceadvanced
Reflow, Repaint, and Layout Thrashing
The two expensive rendering steps triggered by DOM/style changes, and the anti-pattern of alternating reads and writes that forces the browser to recalculate layout repeatedly.
Two rendering steps, with very different costs.
Layout thrashing is like repeatedly asking a mover 'how much does the truck weigh right now?' immediately after loading each individual box, forcing them to stop and put the truck on a scale after every single box, instead of letting them load the entire truck first and weigh it just once at the very end.
Key Concepts
1
reflow (layout) recompute geometry -- positions and sizes.
Expensive; may affect the whole page.
repaint redraw pixels without recomputing layout.
Cheaper.2
What triggers which.
reflow width, height, padding, margin, font-size,
adding or removing elements, reading offsetHeight
repaint color, background-color, visibility, box-shadow
neither transform, opacity -- these run on the compositor3
That last line is the practical one: animating transform and opacity avoids both steps entirely, which
is why every animation guide recommends them over left and top.
transformopacitylefttop
4
Layout thrashing is the anti-pattern.
// forces a reflow on every iteration
elements.forEach(el => {
el.style.height = el.offsetHeight + 10 + 'px';
});5
Reading offsetHeight forces the browser to flush pending style changes and recompute layout. Writing
invalidates it again. Alternating reads and writes means a full layout per element.
offsetHeight
6
The fix is to batch: read everything, then write everything.
const heights = elements.map(el => el.offsetHeight); // all reads
elements.forEach((el, i) =>
el.style.height = heights[i] + 10 + 'px'); // all writes7
One layout instead of a thousand. The code is barely different and the difference is measurable
immediately.
8
The properties that force layout when read.
offsetTop/Left/Width/Height
clientTop/Left/Width/Height
scrollTop/Left/Width/Height
getComputedStyle()
getBoundingClientRect()9
Any of these inside a loop that also writes is thrashing.
10
Other reductions.
build offscreen, insert once a DocumentFragment
toggle a class one style recalculation, not many
position: absolute / fixed removes the element from normal
flow, so its changes affect less
will-change: transform promotes to its own layer --
use sparingly, it costs memory11
How to confirm it. The Performance panel shows purple layout bars. A long sequence of them during one
interaction is thrashing, and the call tree names the line that forced each one.
12
What the interviewer is probing.1. "What is layout thrashing?" Probing: the pattern. Stalls: "Slow rendering." Moves up:
alternating reads and writes of layout properties in a loop, forcing a synchronous reflow each time
instead of one batched at the end.
13
2. "How do you fix it?" Probing: the technique. Stalls: "Use requestAnimationFrame." *Moves
up:* batch all reads first, then all writes, so the browser recalculates once.
14
3. "Which properties force a synchronous layout?" Probing: the specifics. Stalls: "All of
them." Moves up: offsetTop, offsetHeight, getBoundingClientRect, scrollTop and getComputedStyle —
reading them flushes pending changes.
15
4. "Which properties animate without layout?" Probing: the cheap path. Stalls: "Any of
them." Moves up: transform and opacity are composited, so they skip layout and paint entirely —
animating top or width does not.