Cls Budget
Set a CLS budget of 0.1 (Lighthouse synthetic, mobile preset). Block PRs whose budget regression is >0.05 above main. Track field CLS via RUM (web-vitals.js + analytics endpoint) and alert on rolling-p75 ≥ 0.…
$ prime install @community/rule-cls-budget Projection
Always in _index.xml · the agent never has to ask for this.
ClsBudget [rule] v1.0.0
Every page must enforce a Cumulative Layout Shift (CLS) budget of ≤ 0.1 (Google's 'Good' threshold). CI fails the build when synthetic measurement crosses the threshold; production RUM rolling-p75 above 0.1 triggers an alert.
Set a CLS budget of 0.1 (Lighthouse synthetic, mobile preset). Block PRs whose budget regression is >0.05 above main. Track field CLS via RUM (web-vitals.js + analytics endpoint) and alert on rolling-p75 ≥ 0.1 over a 24h window. Reserve dimensions for every image (
width/heightHTML attrs ORaspect-ratioCSS), every iframe, every ad slot, and every async-loaded section above the fold. Usefont-display: optionalorswappaired withsize-adjust/ascent-overrideto eliminate FOUT-induced shifts. Animate onlytransformandopacity— nevertop/left/width/heightfor hover/focus/state transitions.
Loaded when retrieval picks the atom as adjacent / supporting.
ClsBudget [rule] v1.0.0
Every page must enforce a Cumulative Layout Shift (CLS) budget of ≤ 0.1 (Google's 'Good' threshold). CI fails the build when synthetic measurement crosses the threshold; production RUM rolling-p75 above 0.1 triggers an alert.
Set a CLS budget of 0.1 (Lighthouse synthetic, mobile preset). Block PRs whose budget regression is >0.05 above main. Track field CLS via RUM (web-vitals.js + analytics endpoint) and alert on rolling-p75 ≥ 0.1 over a 24h window. Reserve dimensions for every image (
width/heightHTML attrs ORaspect-ratioCSS), every iframe, every ad slot, and every async-loaded section above the fold. Usefont-display: optionalorswappaired withsize-adjust/ascent-overrideto eliminate FOUT-induced shifts. Animate onlytransformandopacity— nevertop/left/width/heightfor hover/focus/state transitions.
Applies To
- Public-facing marketing pages (highest SEO leverage)
- Product detail pages with images, videos, and dynamic specs
- Article and blog pages with embeds (Twitter, YouTube, CodePen)
- App shell loading states — placeholders must match final dimensions
- Any page that monetizes via ads
Implementation Checklist
- Lighthouse CI configured with
assertions: { 'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }] } - Every
has explicit width and height attributes (or aspect-ratio CSS)
- Every
- Ad slots have
min-heightreserved before request fires; container does not collapse if ad fails - Webfont strategy:
font-display: optionalfor body OR swap withsize-adjust/ascent-overridematched to fallback metrics (use Capsize / Fontaine to compute) - Cookie banner overlays via
position: fixed; never pushes content down - Skeleton loaders match final content dimensions exactly (test with screenshots)
- RUM client sends CLS to analytics with
getCLS({reportAllChanges: true})from web-vitals.js
Severity
block
Counter Examples
with no width/height — image loads, pushes content down by 600px, CLS = 0.4 on first paint.- Cookie banner appended to with display: block — pushes hero text down 80px on every visit. CLS = 0.18.
- Web font swap from system to Inter with no size-adjust — line heights change between FOUT and FOIT, CLS spikes 0.15 on font load.
Loaded when retrieval picks the atom as a focal / direct hit.
ClsBudget [rule] v1.0.0
Every page must enforce a Cumulative Layout Shift (CLS) budget of ≤ 0.1 (Google's 'Good' threshold). CI fails the build when synthetic measurement crosses the threshold; production RUM rolling-p75 above 0.1 triggers an alert.
Set a CLS budget of 0.1 (Lighthouse synthetic, mobile preset). Block PRs whose budget regression is >0.05 above main. Track field CLS via RUM (web-vitals.js + analytics endpoint) and alert on rolling-p75 ≥ 0.1 over a 24h window. Reserve dimensions for every image (
width/heightHTML attrs ORaspect-ratioCSS), every iframe, every ad slot, and every async-loaded section above the fold. Usefont-display: optionalorswappaired withsize-adjust/ascent-overrideto eliminate FOUT-induced shifts. Animate onlytransformandopacity— nevertop/left/width/heightfor hover/focus/state transitions.
Applies To
- Public-facing marketing pages (highest SEO leverage)
- Product detail pages with images, videos, and dynamic specs
- Article and blog pages with embeds (Twitter, YouTube, CodePen)
- App shell loading states — placeholders must match final dimensions
- Any page that monetizes via ads
Implementation Checklist
- Lighthouse CI configured with
assertions: { 'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }] } - Every
has explicit width and height attributes (or aspect-ratio CSS)
- Every
- Ad slots have
min-heightreserved before request fires; container does not collapse if ad fails - Webfont strategy:
font-display: optionalfor body OR swap withsize-adjust/ascent-overridematched to fallback metrics (use Capsize / Fontaine to compute) - Cookie banner overlays via
position: fixed; never pushes content down - Skeleton loaders match final content dimensions exactly (test with screenshots)
- RUM client sends CLS to analytics with
getCLS({reportAllChanges: true})from web-vitals.js
Severity
block
Counter Examples
with no width/height — image loads, pushes content down by 600px, CLS = 0.4 on first paint.- Cookie banner appended to with display: block — pushes hero text down 80px on every visit. CLS = 0.18.
- Web font swap from system to Inter with no size-adjust — line heights change between FOUT and FOIT, CLS spikes 0.15 on font load.
Examples
- Vercel: ships CLS budgets via @vercel/speed-insights; blocks deploys when synthetic CLS regresses ≥ 0.05.
- Smashing Magazine: applied
aspect-ratioto all images + size-adjust on Mija/Elena fonts — CLS dropped from 0.32 to 0.04. - Lighthouse CI:
lhci autorunin GitHub Actions on every PR; comments synthetic CLS delta in PR description.
Relations
enhances: @community/metric-cls-cumulative-layout-shift
Rationale
CLS is one of three Core Web Vitals; Google ranks search results on it (since June 2021). Beyond SEO, CLS directly correlates with mis-tap rate: when an ad or banner appears where a button was, users tap the wrong target. Field studies (Google CrUX, Vercel Speed Insights) show median CLS is 0.05–0.15 on the average site — most failures are preventable by reserving space for known layout participants. The budget is enforceable; what gets measured gets fixed.
Applies To
- Public-facing marketing pages (highest SEO leverage)
- Product detail pages with images, videos, and dynamic specs
- Article and blog pages with embeds (Twitter, YouTube, CodePen)
- App shell loading states — placeholders must match final dimensions
- Any page that monetizes via ads
Implementation Checklist
- Lighthouse CI configured with
assertions: { 'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }] } - Every
has explicit width and height attributes (or aspect-ratio CSS)
- Every
- Ad slots have
min-heightreserved before request fires; container does not collapse if ad fails - Webfont strategy:
font-display: optionalfor body OR swap withsize-adjust/ascent-overridematched to fallback metrics (use Capsize / Fontaine to compute) - Cookie banner overlays via
position: fixed; never pushes content down - Skeleton loaders match final content dimensions exactly (test with screenshots)
- RUM client sends CLS to analytics with
getCLS({reportAllChanges: true})from web-vitals.js
Severity
block
Counter Examples
with no width/height — image loads, pushes content down by 600px, CLS = 0.4 on first paint.- Cookie banner appended to with display: block — pushes hero text down 80px on every visit. CLS = 0.18.
- Web font swap from system to Inter with no size-adjust — line heights change between FOUT and FOIT, CLS spikes 0.15 on font load.
Enhances
@community/metric-cls-cumulative-layout-shift
Source
prime-system/examples/frontend-design/primes/compiled/@community/rule-cls-budget/atom.yaml