Skip to content

Frames, layout thrashing and compositing

Measure when geometry is ready; avoid repeatedly asking the browser to rebuild it inside one operation.

Predict first

Before you read: predict

A proctor tile starts at width 100px with clean layout. One callback executes the following.

How many synchronous Layout records occur inside it?

Code for this question
for (let i = 0; i < 4; i++) {  tile.style.width = `${101 + i}px`;  log(tile.offsetWidth);}
Pick one

The 30-second version

A frame may run JavaScript, calculate styles, lay out geometry, paint pixels, then composite layers. A geometry write invalidates layout; a subsequent geometry read can force it immediately. Alternating writes and reads repeats that work. Batch compatible operations. Transform and opacity can avoid layout and paint on compositor layers. A requestAnimationFrame callback runs before the frame's normal rendering work.

Measure when geometry is ready; avoid repeatedly asking the browser to rebuild it inside one operation.

How it works

Step 1 of 7

JavaScript changes state; style resolves rules; layout calculates geometry; paint records drawing; composite combines layers. S1

Analogy: Adjusting a surveyor's tripod

An operator moves one leg, checks a spirit level, moves another leg, and checks again. Each check after an adjustment concerns a new geometry. If the task permits it, the operator makes all planned adjustments and checks once. A second glance with no adjustment uses the same configuration.

Tripod scene Browser mechanism
Leg position changed Geometry invalidated
Inspecting the new level Reading current geometry
Inspection after each adjustment Repeated synchronous layout
All compatible adjustments before inspection Batched writes followed by measurement

In real terms: schedule measurements around the geometry they actually need. Breaks down when: real surveying requires feedback after each move; some browser algorithms do too. Batching is valid only if the dependency permits it. Contrasting case: repainting a coloured mark does not move a tripod leg; similarly, not every visual change requires layout. S1

The task and microtask queues belong to the event-loop record. Interaction phases belong to INP. Neither scheduling vocabulary alone nor knowing that a click is slow identifies a layout dependency.

Examples, run for real

4.1 ExamHall: repeated measurements

EXH-1590, Proctor tile loop forces repeated synchronous layout. The live-feed summary box starts with clean geometry. Eight updates each change its width and immediately read offsetWidth. mechanisms.mjs brackets the callback with performance marks and counts Chromium Layout records between them. Every mutation changes the numeric width, so this is not a test of redundant assignments. S2

worked layout counts: interleaved=8 batched=1 reads-only=0

MR !1790, Batch tile geometry mutations before measurement, keeps the final geometry requirement but moves its read after the compatible updates. That produces one synchronous layout. The reads-only control measures a clean tree and produces none. This repair is suitable when intermediate measurements are unused; if each update depends on its own measured result, silently moving all reads would change the program. S2

4.2 Catalog: choosing the visual property

A promoted product badge is moved using transform; another run varies its opacity. Each run also reads offsetWidth, keeping the measurement operation visible. Both have zero synchronous layouts. Controls using width mutations do require layout. These observations establish the geometry distinction, not a universal promise that any transform animation is free. Initial layer creation, rasterisation and unrelated page changes remain possible costs. S3

worked visual property counts: transform=0 opacity=0 width=1

4.3 A callback is before the rendering work

A badge's requestAnimationFrame callback changes width without reading geometry. A following rendering opportunity completes the observation:

worked rAF trace after callback: UpdateLayoutTree -> Layout -> Paint

This distinguishes a callback scheduled before rendering from a callback after pixels are painted. It does not promise one paint for every callback or a fixed frame rate. The fixture is visible, changes geometry, and waits for the next animation callback to collect its trace. S4

Try it

Answer first, then check. Nothing is saved.

Question 1 of 5

A product panel receives five different width assignments, then one offsetWidth read. It begins clean.

How many synchronous layouts occur inside the callback?

Pick one

Question 2 of 5

A relatively positioned badge must move through three requested horizontal positions. Its width measurement is needed during the callback.

Which implementation avoids synchronous layouts while moving it?

Pick one

Question 3 of 5

A visible tile changes height inside requestAnimationFrame, without reading geometry there.

Which trace order follows the callback-end mark?

Pick one

Question 4 of 5

A review groups six price-panel width updates into three pairs. After each pair it reads offsetWidth. The reviewer says pairing the writes has removed all repeated layout.

Which diagnosis fits the callback?

Pick one

Question 5 of 5

A panel starts at 100px. Seven serial pricing rules each set its next width to Math.round(currentRenderedWidth * 1.1).

What final width does the browser model return?

Pick one

Go deeper

Pro tip

Name performance marks around the exact operation under investigation before recording a trace. This makes it possible to distinguish work inside the callback from later rendering. Tool move, not an assessment repair; User Timing API, read 2026-09-29.

Sources

Fetched 2026-09-29; Chromium observations apply to 153.0.8010.12.

Checked against the tools and docs as of 2026-09-29.