v148 · origin trial · Performance
Forced Reflow Detector
Identifies forced synchronous layouts by triggering common "reflow-triggering reads" and measuring the styleAndLayoutDuration reported in LoAF entries. Shows how batching with requestAnimationFrame eliminates the cost.
reflow triggers
Each row below is a DOM property that forces the browser to flush pending style + layout before it can return a value. Run the detector to measure how much styleAndLayoutDuration each one costs inside a long frame.
Trigger catalog
-
el.offsetHeight
—
-
el.offsetWidth
—
-
el.getBoundingClientRect()
—
-
el.clientHeight
—
-
el.scrollTop
—
-
el.getClientRects()
—
-
window.getComputedStyle()
—
-
el.offsetParent
—
-
el.scrollHeight
—
-
el.offsetTop
—
LoAF metrics
before / after: the fix pattern
A single forced reflow per iteration can balloon styleAndLayoutDuration. Batching all writes before reads eliminates mid-tick forced flushes.
// Interleaved read/write → forces flush each iteration
items.forEach(el => {
el.style.width = '100px'; // write
const h = el.offsetHeight; // read ← FLUSH
el.style.height = h + 'px'; // write
});
// Read phase: collect all geometry
const heights = items.map(el => el.offsetHeight);
requestAnimationFrame(() => {
// Write phase: apply in next frame
items.forEach((el, i) => {
el.style.height = heights[i] + 'px';
});
});
event log
Ready. Click "Run detector" to start.
how it works
A PerformanceObserver watches for long-animation-frame entries. Each "run" pumps 10 forced reflows in a tight loop — reading a layout property immediately after a style mutation — then reads the LoAF entry's new styleAndLayoutDuration field to quantify the cost. The "batched" run separates all writes from all reads, which eliminates intermediate flushes and reduces styleAndLayoutDuration to near-zero.
const obs = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
// Chrome 148: styleAndLayoutDuration is the new breakdown field
console.log('styleAndLayout:', entry.styleAndLayoutDuration);
// Also available: entry.renderDuration, entry.scriptDuration
}
});
obs.observe({ type: 'long-animation-frame', buffered: true });
references
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗