What shifted
What kind of element moved in the captured layout shifts (heuristic, top-5 shifts per site).
At a glance the headline numbers for What shifted
What kind of element moved in the captured layout shifts (heuristic, top-5 shifts per site).
2.1% of captured layout shifts trace back to unsized media. Font swaps account for 6.1%.
The what shifted mix who uses what, and how stable each group is
What shifted. On the fleet: 82.9% box grow, 8.4% displaced, 6.1% font text. 78.7% of sites use at least one box_grow.
Passing CLS per bucket every category and count level at once - color is the pass rate
Each row is a category, each column its own count bucket (few on the left, many on the right); the cell is the share of those sites passing CLS.
Displaced swings the hardest: 75% of sites pass CLS with few, 29% with many. computed
Few vs many - does quantity cost CLS? the pass rate with few vs many of each category
Per category: the pass rate among pages with FEW of it (hollow ring) against pages with MANY (solid dot), worst trend first. Thin buckets are excluded from the endpoints.
More Displaced costs the most: the CLS pass rate falls from 75% with few to 29% with many. computed
Why this matters for the Core Web Vitals, and where to start fixing it
CLS tells you how much the page moved. This metric tells you what moved, and that decides the fix. An image without dimensions pushes everything below it down when it arrives. A swapped web font reflows whole paragraphs of text. An injected embed, banner or ad shoves the content aside after the page looked done.
Each element type has its own cure. Images need width and height so the browser reserves the box. Text needs a font-display strategy and a fallback font with matching metrics. Embeds and ads need a fixed slot that exists before they load. Identify the element first, then apply the matching fix.
Chrome field data from 189,915 sites, representing millions of real page loads. How we measured.
Live queries (2) — admin only
SELECT 1 AS ok FROM site_metric_bags LIMIT 0;
WITH flat AS (
SELECT b.cat, b.n, b.size, s.crux."desktop".cls AS cwv_val
FROM site_metric_bags b
JOIN sites s ON s.origin = b.origin
WHERE b.path = 'cls.attribution'
AND b.cat IS NOT NULL
),
totals AS (
SELECT cat,
SUM(n) AS fleet_n,
SUM(size) AS fleet_size,
COUNT(*) FILTER (WHERE n IS NOT NULL) AS sample,
COUNT(*) FILTER (WHERE n > 0) AS with_any,
quantile_disc(n, 0.95) AS p95,
COUNT(*) AS n_rows
FROM flat
GROUP BY cat
),
widths AS (
SELECT *,
GREATEST(1, CAST(round(COALESCE(p95, 0)) AS INTEGER)) AS cap,
LEAST(GREATEST(1, CAST(round(COALESCE(p95, 0)) AS INTEGER)), 12 - 1) AS regular_buckets
FROM totals
),
widths2 AS (
SELECT *,
GREATEST(1, CAST(ceil(cap * 1.0 / regular_buckets) AS INTEGER)) AS width
FROM widths
),
binned AS (
SELECT f.cat, f.cwv_val, w.fleet_n, w.fleet_size, w.sample, w.with_any, w.width, w.regular_buckets,
CASE WHEN f.n IS NULL THEN NULL
ELSE LEAST(CAST(FLOOR(f.n * 1.0 / w.width) AS INTEGER), w.regular_buckets)
END AS bucket_idx
FROM flat f
JOIN widths2 w ON f.cat = w.cat
)
SELECT cat, fleet_n, fleet_size, sample, with_any, width, regular_buckets,
bucket_idx,
COUNT(*) AS n,
quantile_disc(cwv_val, 0.5) AS median,
COUNT(*) FILTER (WHERE cwv_val IS NOT NULL) AS total_cwv,
COUNT(*) FILTER (WHERE cwv_val IS NOT NULL AND cwv_val <= 0.1) AS good
FROM binned
WHERE bucket_idx IS NOT NULL
GROUP BY cat, fleet_n, fleet_size, sample, with_any, width, regular_buckets, bucket_idx
ORDER BY cat, bucket_idx;