Shift concentration

How concentrated the shifting is: largest shift over total shift.

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

At a glance the headline numbers for Shift concentration

How concentrated the shifting is: largest shift over total shift.

1
on the typical site
half of sites sit at or below
1
1 in 4 sites exceed this
the top quarter
6
the heaviest 1%
the long tail
121,037
sites measured
all-device field data

On the typical site, the largest single shift causes 1 of all layout shift.

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

Shift concentration the value at each percentile across all sites

0.5
p10
0.7
p25
1.0
p50
1
p75
1
p90
6.2
p99

Shift concentration 1.0. p75 1. p99 6.2. computed

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

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

Two sites can have the same CLS for opposite reasons. One has a single big jump. The other moves a little, everywhere, all the time. This ratio separates them: the largest shift divided by the total. Close to one means one event causes nearly all the damage. Find that element, reserve its space, and the score follows.

A low concentration is the harder case. No single shift looks bad, but they add up. That pattern points at scroll-triggered animations, CSS transitions on layout properties, or content that streams in piece by piece. There is no one bug to fix, so it needs a structural pass instead of a patch.

Related signals Largest single shift → Layout shift count → Shift direction → What shifted → Chrome field data from 189,915 sites, representing millions of real page loads · How we measured
Live queries (2) — admin only
Query #1: 273.3 ms
SELECT COUNT(*) AS count,
            quantile_disc(m.cls.concentration, 0.10) AS p10,
            quantile_disc(m.cls.concentration, 0.25) AS p25,
            quantile_disc(m.cls.concentration, 0.50) AS p50,
            quantile_disc(m.cls.concentration, 0.75) AS p75,
            quantile_disc(m.cls.concentration, 0.90) AS p90,
            quantile_disc(m.cls.concentration, 0.99) AS p99
            FROM sites WHERE m.cls.concentration IS NOT NULL;
Query #2: 16.9 ms
SELECT CASE WHEN m.cls.concentration >= 0 AND m.cls.concentration < 1 THEN 0 WHEN m.cls.concentration >= 1 THEN 1 END AS bucket_idx, COUNT(*) AS n,
            quantile_disc(crux."all".inp, 0.5) AS median,
            COUNT(*) FILTER (WHERE crux."all".inp IS NOT NULL AND crux."all".inp <= 200) * 1.0 / NULLIF(COUNT(*) FILTER (WHERE crux."all".inp IS NOT NULL), 0) AS good_pct
            FROM sites WHERE m.cls.concentration IS NOT NULL GROUP BY bucket_idx;
JSON file lookups (4)
20260625/meta.json 0.04 ms
20260625/types.json 0.73 ms
20260625/loaf-scripts.json 0.52 ms
20260625/menu.json 0.19 ms