Forced Reflow

Forced reflow occurs when JavaScript requests layout-dependent information after a DOM or style change has invalidated layout, causing the browser to calculate layout synchronously. Frequent forced reflows can make interactions and animations slow by interrupting the browser’s normal rendering pipeline.

Browsers generally separate rendering work into stages such as style calculation, layout, painting, and compositing. After a DOM or CSS change, the browser can often defer some of this work until it is needed. This allows multiple changes to be grouped together efficiently.

A forced reflow occurs when JavaScript reads a value whose result depends on up-to-date layout after previously making a change that invalidated layout. Examples include reading `offsetWidth`, `offsetHeight`, `getBoundingClientRect()`, or certain computed style values. To return an accurate value, the browser may have to perform layout immediately instead of waiting for its normal rendering opportunity.

The common performance problem is alternating writes and reads. For example, code might change an element's class, immediately read its geometry, change another element, and read geometry again. Each read can potentially force the browser to resolve pending layout work, producing repeated layout calculations within one JavaScript task.

A common optimization is to separate DOM writes from layout reads. Gather the measurements first, perform the required mutations afterward, or batch reads and writes into appropriate phases. APIs such as `requestAnimationFrame()` can also help coordinate visual updates with the browser's rendering cycle, although they do not automatically eliminate every layout calculation.

Forced reflow is different from all layout work being inherently bad. Layout is a normal part of rendering, and a single necessary layout calculation may be inexpensive. The concern is unnecessary or repeated synchronous layout work, especially when it occurs inside high-frequency handlers such as scrolling, dragging, resizing, or animation code.

Key points

Interview questions

What is layout thrashing, and how would you prevent it?

Layout thrashing is excessive layout work caused by repeatedly alternating operations that invalidate layout with operations that require fresh layout information. A common fix is to batch layout reads together and perform writes separately. This gives the browser fewer opportunities to repeatedly resolve invalidated geometry. Profiling should be used to verify that the change actually improves the workload.

What is forced reflow, and why can it hurt frontend performance?

Forced reflow happens when JavaScript needs current layout information and the browser must calculate layout immediately. This commonly occurs after code has changed the DOM or styles in a way that invalidates layout. The synchronous calculation can delay other JavaScript and rendering work. Repeated occurrences are particularly costly in frequently executed code.

Give an example of code that can cause forced reflow.

A typical pattern is to mutate an element and immediately read its geometry. For example, adding a class that changes dimensions can invalidate layout, and calling `getBoundingClientRect()` afterward requires current geometry. The browser may therefore perform layout before returning the measurement. Repeating this write-read sequence can amplify the cost.

Does changing any CSS property cause reflow?

No. The rendering consequences depend on what the property changes and what the browser must recalculate. Changes that affect geometry or relationships between elements can require layout, while some visual changes can be handled through repaint or compositing without layout. The exact cost therefore depends on the property, document structure, and rendering circumstances.

How would you diagnose forced reflow in a real application?

I would first reproduce the slow interaction and record it with browser performance tooling. In the trace, I would look for layout events and correlate them with JavaScript call stacks and DOM operations. I would then inspect whether code is alternating mutations with geometry-dependent reads, particularly in high-frequency handlers. After restructuring the code, I would profile again to confirm that layout work and interaction latency actually decreased.