Layout (Reflow) in Browser Rendering

Layout calculates the geometry and position of rendered elements from their styles, content, and surrounding constraints. It determines where boxes appear and how large they are before the browser paints them.

After the browser has determined an element's styles, the layout step computes its physical geometry: dimensions, positions, and relationships to neighboring elements. This process is also called reflow when layout work is triggered again after a relevant change.

Layout considers factors such as the containing block, available width, intrinsic content size, margins, padding, borders, and the rules of the relevant layout system such as normal flow, Flexbox, or Grid. A change to geometry-related properties can therefore require recalculating affected parts of the document.

Layout is distinct from painting. Layout answers "where and how big?" while painting turns the resulting boxes into pixels such as backgrounds, borders, text, and images. Compositing can then combine painted layers for display.

JavaScript can sometimes force the browser to perform pending layout work synchronously by reading geometry after making style changes. Common geometry reads include `offsetWidth`, `offsetHeight`, and `getBoundingClientRect()`. Repeatedly alternating writes and such reads can cause layout thrashing.

Key points

Interview questions

What does the browser do during layout?

During layout, the browser calculates the size and position of rendered elements. It uses information such as computed styles, content dimensions, and constraints from containing and neighboring elements. The result is geometry that later rendering stages can use to paint the page.

What is reflow?

Reflow commonly refers to recalculating layout after something changes that affects geometry. For example, changing an element's width can alter its own geometry and potentially affect descendants or nearby content. The amount of work depends on what parts of the document are affected.

Why can reading getBoundingClientRect() after a style change be expensive?

A style or DOM write may leave layout work pending. If code immediately requests geometry with `getBoundingClientRect()`, the browser may need to perform that pending layout work synchronously to provide an up-to-date result. Repeating write-read-write-read sequences can therefore create layout thrashing.

Does changing any CSS property always trigger layout?

No. The rendering consequences depend on what the property changes. A property that changes geometry, such as `width`, can require layout, while a change that only affects visual appearance may only require painting or compositing. The exact behavior also depends on the browser and surrounding document state.

How would you reduce layout-related performance problems in a frontend application?

First, identify whether the application is doing excessive layout work rather than assuming that every rendering problem is caused by layout. Batch DOM and style writes instead of repeatedly alternating them with geometry reads. Reduce unnecessary DOM changes and use browser performance tools to identify forced layouts and expensive layout passes. The appropriate optimization depends on the measured bottleneck.