# Cumulative layout shift (CLS) in Vanilla JS

> How to fix cumulative layout shift (cls) in Vanilla JS — with the exact fix and copy-paste code.

_Category: Performance · Detector `layout-thrashing` · Severity: warning_

Layout shift is when content jumps after it has already rendered — an image loads and pushes the text down, a banner injects itself above the fold, a web font swaps and reflows everything. It is a Core Web Vitals metric Google ranks on, and it makes users tap the wrong thing. AI-built pages shift constantly because generated markup omits `width`/`height` on images and drops late content in without reserving space.

## The fix for Vanilla JS

Set the `width` and `height` attributes on media, and wrap embeds in an `aspect-ratio` box. Never `document.body.prepend()` content above what the user is already reading.

```html
<img src="/hero.jpg" width="1200" height="630" alt="Hero" style="width:100%;height:auto" />
```

### Steps

1. Add `width` and `height` (or `aspect-ratio`) to every image, video, and iframe
2. Reserve a fixed-size slot for anything injected after load (ads, banners, embeds)
3. Use `font-display: optional` or a size-adjusted fallback to avoid font-swap reflow

## How VibeCheck detects it

The `layout-thrashing` detector flags this live in the browser and reports it to the widget's Problems list — and to your coding agent over MCP.

- **Issue string:** `Layout shift cluster detected (3 shifts)`
- **Threshold:** ≥ 3 layout shifts within a 500ms window, with no recent user input

## FAQ

### What CLS score do I need?

Google considers CLS good at 0.1 or below, and poor above 0.25, for 75% of page loads. It is one of the three Core Web Vitals used in ranking.

### Why does the layout-thrashing detector flag this?

VibeCheck observes the browser’s layout-shift entries. When three or more fire within 500ms without user input, it flags a cluster — that burst is exactly what a jumpy load feels like.

### My image is responsive — do I still set `width` and `height`?

Yes. Set the intrinsic `width`/`height` attributes so the browser knows the aspect ratio, then use CSS (`width:100%`; `height:auto`) to scale it. That gives you responsiveness with zero shift.

See the general, framework-agnostic fix: https://vibecheck.wcgw.fun/fix/cumulative-layout-shift.md

---

Fix guide from VibeCheck — https://vibecheck.wcgw.fun/fix/cumulative-layout-shift. Full site index for LLMs: https://vibecheck.wcgw.fun/llms.txt
