Because something loaded late and pushed the layout down. An image without dimensions, a web font swapping in, or a cookie banner appearing all move content that was already on screen. Google measures this as Cumulative Layout Shift, and it is one of the three Core Web Vitals.
It is the most personally annoying performance problem on the web. Everyone has tried to tap a link and hit an ad instead because the page moved a fraction of a second earlier. That moment is a measurable number, and it is a number Google collects from real visitors.
The good news is that CLS is the most fixable of the three Core Web Vitals. Most of the causes are structural, they show up in a handful of predictable places, and the fixes are usually small changes rather than a rebuild.
CLS measures unexpected movement of visible content while a page loads. Google's own web.dev documentation defines it as a measure of the largest burst of layout shift scores for every unexpected layout shift during the page lifecycle. It is scored as a number, not in seconds, which is why it confuses people.
Google publishes clear thresholds. A CLS of 0.1 or less is good. Between 0.1 and 0.25 needs improvement. Above 0.25 is poor. Those thresholds are assessed at the 75th percentile of page loads across mobile and desktop, so you are judged by your slower quarter of visitors, not your average.
That percentile detail matters more than the threshold itself. A site can feel perfectly stable on a fast laptop on office wifi and still fail, because CLS is collected from real people on real phones on real networks.
Each shift gets a score of impact fraction multiplied by distance fraction. Impact fraction is how much of the viewport the moving elements covered across two frames. Distance fraction is the furthest any unstable element moved, horizontally or vertically, divided by the viewport's largest dimension.
Then Google groups shifts into session windows. A session window is one or more shifts happening in rapid succession, with less than one second between individual shifts and a maximum total window of five seconds. Your CLS is the score of the worst window, not the sum of everything that ever moved.
This is why one bad moment can sink an otherwise stable page. A single banner that pushes half the viewport down a long way scores far worse than twenty tiny nudges spread across the load.
It also explains a trap we see often. Teams fix the small shifts they can see easily and leave the one big shift that actually sets the score. Always find the worst window first.
It is the easiest of the three to pass, and that is exactly why failing it looks bad. The 2025 Web Almanac, built from HTTP Archive and Chrome UX Report data measured in July 2025, found 81% of mobile pages achieve good CLS. Only 62% achieve good LCP.
Set against the whole picture, 48% of mobile origins passed all three Core Web Vitals and 56% of desktop origins did. So CLS is rarely the metric holding a site back. Largest Contentful Paint usually is, and we broke that one down separately in our guide to fixing Largest Contentful Paint.
Our honest view is that CLS deserves attention for user experience reasons more than ranking reasons. Failing a metric that four out of five sites pass suggests something specific is broken, and it is usually worth an hour to find it.
Four things, and Google's own optimization documentation names all four. Images published without dimensions. Ads, embeds, and iframes with no reserved space around them. Content injected dynamically, like consent banners and signup forms. And web fonts, where swapping from a fallback font changes how the text is laid out.
In the projects we inherit, images and late banners cause the majority of the damage. A hero image with no width and height, a consent banner that appears after a delay, and an embedded video that resizes once its script runs will together produce a genuinely poor score.
The pattern behind all four is the same. The browser did not know how much space something needed, so it laid the page out without it and then had to redo the work. Every fix below is a variation on telling the browser the size in advance.
Give every image explicit width and height attributes in the HTML, or set the CSS aspect-ratio property. Modern browsers use those numbers to reserve the correct box before the file arrives, so nothing moves when it does. This one change fixes most image-driven shift.
The attributes do not lock your layout. You still control the displayed size with CSS, and the browser combines the intrinsic ratio from the attributes with your styles. People skip width and height because they assume it fights responsive design, and it does not.
For images whose ratio varies, such as CMS-driven cards, aspect-ratio in CSS is the cleaner tool because it applies to the container regardless of what fills it. We use this constantly on collection lists, where the editor uploads whatever they have and the layout has to hold.
If you are also compressing and sizing images properly, you get a speed win alongside the stability win. Those two jobs are usually done in the same pass, because both come down to knowing what an image is before you serve it.
Match the fallback font to the web font as closely as possible, then control the swap. Google's guidance recommends font-display: optional to avoid a re-layout entirely, plus the font override descriptors size-adjust, ascent-override, descent-override, and line-gap-override to reduce the size gap between fallback and final font.
The mechanism is simple once you see it. Your fallback font renders text at one size, the web font arrives with slightly different metrics, and every line of text reflows. On a text-heavy page that reflow can move a large share of the viewport a meaningful distance, which is the worst combination for the score.
Self-hosting fonts and preloading the files you actually need above the fold helps, because the swap happens sooner or does not happen at all. We go further into loading strategy in our piece on web font loading and performance.
One practical warning. font-display: optional means the web font may not be used on a first visit if it arrives too late. That is a real design tradeoff, and it should be a decision rather than an accident.
Reserve the space before they load. Google's documentation recommends min-height or aspect-ratio on the container, placing dynamic content lower on the page where possible, and avoiding content injected without user interaction. A slot that is already the right size cannot shift anything.
Cookie and consent banners are the worst repeat offender we see, because they are often added last by a third-party script and nobody tests their layout effect. A banner that overlays the page costs nothing. A banner that pushes the page down costs you the metric.
Embeds from YouTube, calendars, and chat widgets have the same problem in a different wrapper. Their iframes frequently resize once their own scripts run. Setting a fixed aspect ratio on the wrapper solves it, and it also stops the embed from dictating your layout.
The general rule we apply on builds is that anything arriving late gets a box drawn for it first. If we cannot predict its size, it goes below the fold or into an overlay.
Use both lab and field data, because they answer different questions. PageSpeed Insights shows you Chrome UX Report field data from real visitors alongside a Lighthouse lab score. Chrome DevTools shows you exactly which elements moved, which is what you need to actually fix it.
Field data is the one that counts for Core Web Vitals assessment, and it lags. It reflects a trailing window of real visits, so a fix you ship today will not show up immediately. We warn clients about this because the silence after a fix feels like failure when it is just latency in the data.
For diagnosis, the Performance panel in Chrome DevTools with mobile throttling turned on is the fastest path. Record a load, look for the layout shift markers, and click one to see the exact element that moved. Search Console also groups affected URLs, which helps when the problem is template-wide rather than page-specific.
Test on a real phone at least once. Emulated viewports miss things like slow font delivery and third-party scripts behaving differently on mobile networks.
Find your worst session window and fix that single shift. Open the page in Chrome DevTools with throttling on, identify the largest movement, and address it. In most cases it will be an image without dimensions or a late banner, and one change will move the score into passing range.
After that, work through the predictable list. Dimensions on every image, reserved space for every embed, controlled font swapping, and no injected content above the fold. Then confirm the page qualifies for the back and forward cache, which Google notes eliminates shift on repeat navigation entirely. If you want the wider ranking context, our overview of Core Web Vitals and SEO puts CLS in proportion against the other two metrics.
We hold an average PageSpeed score of 98 across our projects, and stability is a big part of how we get there. On Axis Align we shipped a 98 PageSpeed score with a 0.7 second load, and on ION Clean Energy we took load time from 3.4 seconds to 0.8 seconds. If your own scores are stuck and you cannot find the shift, send us the URL and we will take a look. Let's talk, over at phoenix.studio.
Tell us where you want to go. We'll tell you how we'd get you there.