[Violation] Forced reflow medium
Chrome console "[Violation] Forced reflow while executing JavaScript took NNms"
JavaScript read a layout property right after writing to the DOM, forcing the browser to recalculate layout synchronously mid-script.
What you see
[Violation] Forced reflow while executing JavaScript took 53ms
What’s actually happening
A yellow [Violation] warning shows up in the console, usually during scroll, resize, or an animation. The page feels janky — scrolling stutters, interactions lag. The NNms figure is how long the synchronous layout recalculation blocked the main thread; anything over ~30ms is noticeable, and it often repeats every frame.
Common causes
- A loop that writes a style then immediately reads a layout property (el.style.width = x; const h = el.offsetHeight) — each read forces a fresh layout because the write invalidated the last one
- Reading getBoundingClientRect, offsetTop, scrollHeight, or clientWidth inside a scroll or resize handler that also mutates the DOM
- Animating layout-triggering properties (top, left, width, height, margin) via JS instead of transform/opacity
- A third-party script (ads, analytics, sliders) measuring elements repeatedly without batching
- Reading offsetWidth on many elements in one pass while interleaving class changes — classic layout thrashing across a list
How to fix it
- Find the offender in the Performance panelRecord a trace in DevTools Performance while reproducing the jank. Look for tall purple 'Recalculate Style / Layout' bars with a warning triangle; click one and check 'Summary' for the stack. That points you at the exact line reading layout.
- Batch reads, then writesSeparate measurement from mutation. Read all the layout values you need into variables first, then apply all DOM/style changes after. Never read-write-read-write in a loop — that's what forces repeated reflows.
- Defer reads with requestAnimationFrameMove layout reads into a requestAnimationFrame callback so they happen at a consistent point in the frame, after style changes have flushed. For read-then-write patterns, libraries like fastdom formalize this split if hand-batching gets unwieldy.
- Animate with transform and opacity onlyReplace JS-driven top/left/width animations with CSS transform: translate() and opacity, which the compositor handles off the main thread and don't trigger layout. Add will-change sparingly on the animated element.
- Cache layout values outside loopsIf you need a container's width inside a loop over 200 items, read it once before the loop into a const. Re-reading offsetWidth per iteration is the most common accidental thrash.
Stop it recurring
Keep DOM reads and writes in separate phases — measure everything, then mutate everything — and animate only transform/opacity.
Related errors