Layout Instability API CLS
LayoutShift entries, value calculation, hadRecentInput, and how to attribute CLS in the field.
- browser
- cls
- layout-instability
- web-vitals
- performance
CLS (Cumulative Layout Shift) measures unexpected movement of visible content. The Layout Instability API exposes layout-shift performance entries so RUM tools can attribute shifts to nodes and timing — not just a Lighthouse score.
Docs: Layout Instability API, web.dev CLS, Optimize CLS.
What a layout shift entry contains
const po = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) {
console.log(entry.value, entry.sources);
}
}
});
po.observe({ type: 'layout-shift', buffered: true });
| Field | Role |
|---|---|
value |
Shift score contribution |
hadRecentInput |
User interaction window — excluded from CLS if true |
sources |
Nodes that moved (where supported) |
startTime |
When the shift happened |
CLS aggregates shift scores across the page life (session windowing rules apply in the modern metric definition — follow current web.dev details for exact session windows).
Score intuition
Shift impact ≈ distance moved × viewport area fraction. A full-width banner shoving content down scores worse than a tiny badge nudge.
Common causes (field)
- Images/iframes without dimensions
- Fonts swapping metrics (
font-display: swapwithout fallback metrics) - Late ads/embeds injected above existing content
- Dynamic content insertion without reserved space
- Animating
top/heightinstead oftransform
<img src="/hero.avif" width="1200" height="630" alt="" />
.ad-slot {
min-height: 250px;
aspect-ratio: 4 / 1;
}
hadRecentInput matters
Clicks that expand an accordion intentionally move layout; those shifts are excluded when tied to recent input. Don’t “fix” CLS by ignoring product UX — fix unexpected shifts only.
Measuring with web-vitals
import { onCLS } from 'web-vitals';
onCLS(console.log);
Attribution builds help identify the largest shift’s nodes in supporting browsers.
Debugging workflow
- Lab: Performance panel → Experience / Layout Shift regions (Chrome).
- Filmstrip: watch jumps after late loads.
- Field: RUM CLS + page type + device.
- Fix: reserve space, font strategy, stable skeletons.
Product tactics: CLS optimization tactics.
Interview out-loud
“CLS sums unexpected layout shifts from the Layout Instability API. Entries with hadRecentInput don’t count. I reserve space for media and embeds, stabilize fonts, and use onCLS attribution to find the nodes that moved.”
Session windows (intuition)
Modern CLS aggregates shifts in session windows so a single long page doesn’t unfairly sum forever. Still, a big shift late in the visit hurts. Focus on the largest shift attribution nodes; fixing the top one often recovers the metric. Don’t chase 0.001 noise on desktop while mobile PDP banners score 0.25.
Related
Further depth
Teams often under-invest in this topic until an incident or CWV regression. Schedule a one-hour drill: reproduce the failure mode in DevTools, list the top three mitigations for your stack, and file tickets with owners. Revisit after the next major feature that touches networking, rendering, auth, or third parties — those are the moments regressions land. Keep primary documentation links in the runbook so on-call is not searching chat history at 2am.
Concrete artifacts to leave behind: a short architecture note, a CI assertion or header snapshot, and a dashboard panel (lab or field) that would have caught the last bug. Teaching the rest of the team the mental model matters as much as the one-line fix.
Further reading
Related guides
- Event Timing for INPEvent Timing API fields that power INP: input delay, processing, presentation delay, and attribution.
- BFCache Back Forward CacheHow the back/forward cache freezes pages for instant history nav, what blocks it, and how to restore state safely.
- Browser DevTools Network PanelRead waterfalls, timing phases, headers, throttling, and initiator chains in the Network panel like a production debugger.
- Browser DevTools Performance PanelRecord main-thread timelines: long tasks, style/layout/paint, frames, and how to turn flame charts into INP fixes.
- Browser Networking 101DNS, TCP/TLS, HTTP/1.1 vs H2/H3, connection reuse, and what frontend code can actually influence.