Dev.Lib
arrow_backBack to Blogs
LEVEL_033.1June 27, 20261 min read

Layout thrashing

Browser Performance

Interleaving DOM reads (offsetWidth, getBoundingClientRect) with writes forces synchronous layout recalc — "layout thrashing." Batch reads then writes; use `requestAnimationFrame` for visual updates.

Summary

Interleaving DOM reads (offsetWidth, getBoundingClientRect) with writes forces synchronous layout recalc — "layout thrashing." Batch reads then writes; use requestAnimationFrame for visual updates. Virtual DOM doesn't protect against forced sync layout in refs/measurements. DevTools Performance shows "Recalculate Style" / "Layout" spikes.

Code example

// Bad: read-write-read-write forces layout thrashing
elements.forEach((el) => {
  el.style.width = el.offsetWidth + 10 + 'px';
});

// Good: batch reads, then writes
const widths = elements.map((el) => el.offsetWidth);
elements.forEach((el, i) => {
  el.style.width = widths[i] + 10 + 'px';
});

Key points

  • Interleaving DOM reads (offsetWidth, getBoundingClientRect) with writes forces synchronous layout recalc — "layout thrashing." Batch reads then writes; use requestAnimationFrame for visual updates.
  • Virtual DOM doesn't protect against forced sync layout in refs/measurements.
  • DevTools Performance shows "Recalculate Style" / "Layout" spikes.

Further reading

Related concepts