Blocking frame breakdown

The blocking animation frame behind that interaction: script, forced reflow, style/layout, other (lab).

Field data PhoneDesktopAll Scope All sites Q2 2026 edition · Phone field outcomes
Metric LCP INP CLS
1

At a glance the headline numbers for Blocking frame breakdown

The blocking animation frame behind that interaction: script, forced reflow, style/layout, other (lab).

79ms
Median INP stack
the measures at p50
92%
Biggest: Script ms
73ms of the stack
121ms
Headroom at p50
vs the 200ms target

Script accounts for 73ms of the typical blocking frame.

The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
2

Where the milliseconds go the phases at the median, against the budget

Script ms73ms92% of the total Forced reflow ms0ms0% of the total Style layout ms6ms8% of the total Other ms0ms0% of the total 200ms target
Script ms 73ms · 92% Forced reflow ms 0ms · 0% Style layout ms 6ms · 8% Other ms 0ms · 0%

At the median the whole stack uses 79ms, inside the 200ms INP budget. The biggest piece is Script ms at 73ms, 92% of the total. computed

The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
3

Passing CLS per phase the share of sites passing, by how long each phase takes

100% 75% 50% 25%
Script ms Forced reflow ms

Each line is one phase: left = sites where it is quick, right = sites where it drags (buckets, short to long). The steeper the fall, the more that phase decides CLS.

Forced reflow ms falls hardest: from its fastest to its slowest bucket the CLS pass rate drops 4 points, down to 85%. computed

The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
4

The 2 distributions how each phase spreads across sites - color is the share passing in that range

Script ms p50 73ms · p75 123ms
0–99300+
Forced reflow ms p50 0ms · p75 20ms
0–99200+
mostly passing tipping mostly failing

Script ms stays green across its whole range: it never decides CLS. Script ms turns red in its tail - the failing sites live there. computed

The State of Web Vitals · Q2 2026 · 189,915 sites · phone field datacorewebvitals.io/state-of-cwv
5

Why this matters for the Core Web Vitals, and where to start fixing it

The long animation frame behind a slow interaction splits into parts. Script time is JavaScript running. Style and layout time is the browser recomputing the page after changes. Forced reflow is the expensive special case: a script writes to the DOM, then reads a layout value back, and the browser must stop mid-script and lay out the page to answer.

The split decides the fix. Script time wants less work or yielding. Style and layout time wants a smaller scope: a smaller DOM, containment. Forced reflow wants reordered code: batch the reads first, then do the writes.

Related signals Interaction invoker types → Yielding strategy → CSS hints → INP phase breakdown → Chrome field data from 189,915 sites, representing millions of real page loads · How we measured
Live queries (8) — admin only
Query #1: 210.4 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.inp.loaf.script_ms, 0.10) AS p10,
            quantile_disc(m.inp.loaf.script_ms, 0.25) AS p25,
            quantile_disc(m.inp.loaf.script_ms, 0.50) AS p50,
            quantile_disc(m.inp.loaf.script_ms, 0.75) AS p75,
            quantile_disc(m.inp.loaf.script_ms, 0.90) AS p90,
            quantile_disc(m.inp.loaf.script_ms, 0.99) AS p99
            FROM sites WHERE m.inp.loaf.script_ms IS NOT NULL;
Query #2: 219.2 ms
SELECT CASE WHEN m.inp.loaf.script_ms >= 0 AND m.inp.loaf.script_ms < 100 THEN 0 WHEN m.inp.loaf.script_ms >= 100 AND m.inp.loaf.script_ms < 200 THEN 1 WHEN m.inp.loaf.script_ms >= 200 AND m.inp.loaf.script_ms < 300 THEN 2 WHEN m.inp.loaf.script_ms >= 300 THEN 3 END AS bucket_idx, COUNT(*) AS n,
            quantile_disc(crux."phone".cls, 0.5) AS median,
            COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL AND crux."phone".cls <= 0.1) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL), 0) AS good_pct
            FROM sites WHERE m.inp.loaf.script_ms IS NOT NULL GROUP BY bucket_idx;
Query #3: 246.6 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.inp.loaf.forced_reflow_ms, 0.10) AS p10,
            quantile_disc(m.inp.loaf.forced_reflow_ms, 0.25) AS p25,
            quantile_disc(m.inp.loaf.forced_reflow_ms, 0.50) AS p50,
            quantile_disc(m.inp.loaf.forced_reflow_ms, 0.75) AS p75,
            quantile_disc(m.inp.loaf.forced_reflow_ms, 0.90) AS p90,
            quantile_disc(m.inp.loaf.forced_reflow_ms, 0.99) AS p99
            FROM sites WHERE m.inp.loaf.forced_reflow_ms IS NOT NULL;
Query #4: 275.0 ms
SELECT CASE WHEN m.inp.loaf.forced_reflow_ms >= 0 AND m.inp.loaf.forced_reflow_ms < 100 THEN 0 WHEN m.inp.loaf.forced_reflow_ms >= 100 AND m.inp.loaf.forced_reflow_ms < 200 THEN 1 WHEN m.inp.loaf.forced_reflow_ms >= 200 THEN 2 END AS bucket_idx, COUNT(*) AS n,
            quantile_disc(crux."phone".cls, 0.5) AS median,
            COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL AND crux."phone".cls <= 0.1) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL), 0) AS good_pct
            FROM sites WHERE m.inp.loaf.forced_reflow_ms IS NOT NULL GROUP BY bucket_idx;
Query #5: 219.1 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.inp.loaf.style_layout_ms, 0.10) AS p10,
            quantile_disc(m.inp.loaf.style_layout_ms, 0.25) AS p25,
            quantile_disc(m.inp.loaf.style_layout_ms, 0.50) AS p50,
            quantile_disc(m.inp.loaf.style_layout_ms, 0.75) AS p75,
            quantile_disc(m.inp.loaf.style_layout_ms, 0.90) AS p90,
            quantile_disc(m.inp.loaf.style_layout_ms, 0.99) AS p99
            FROM sites WHERE m.inp.loaf.style_layout_ms IS NOT NULL;
Query #6: 199.7 ms
SELECT CASE WHEN m.inp.loaf.style_layout_ms >= 0 AND m.inp.loaf.style_layout_ms < 100 THEN 0 WHEN m.inp.loaf.style_layout_ms >= 100 THEN 1 END AS bucket_idx, COUNT(*) AS n,
            quantile_disc(crux."phone".cls, 0.5) AS median,
            COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL AND crux."phone".cls <= 0.1) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL), 0) AS good_pct
            FROM sites WHERE m.inp.loaf.style_layout_ms IS NOT NULL GROUP BY bucket_idx;
Query #7: 186.5 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.inp.loaf.other_ms, 0.10) AS p10,
            quantile_disc(m.inp.loaf.other_ms, 0.25) AS p25,
            quantile_disc(m.inp.loaf.other_ms, 0.50) AS p50,
            quantile_disc(m.inp.loaf.other_ms, 0.75) AS p75,
            quantile_disc(m.inp.loaf.other_ms, 0.90) AS p90,
            quantile_disc(m.inp.loaf.other_ms, 0.99) AS p99
            FROM sites WHERE m.inp.loaf.other_ms IS NOT NULL;
Query #8: 190.5 ms
SELECT CASE WHEN m.inp.loaf.other_ms >= 0 AND m.inp.loaf.other_ms < 100 THEN 0 WHEN m.inp.loaf.other_ms >= 100 THEN 1 END AS bucket_idx, COUNT(*) AS n,
            quantile_disc(crux."phone".cls, 0.5) AS median,
            COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL AND crux."phone".cls <= 0.1) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."phone".cls IS NOT NULL), 0) AS good_pct
            FROM sites WHERE m.inp.loaf.other_ms IS NOT NULL GROUP BY bucket_idx;
JSON file lookups (4)
20260625/meta.json 0.02 ms
20260625/types.json 0.50 ms
20260625/loaf-scripts.json 0.47 ms
20260625/menu.json 0.11 ms