Cumulative Layout Shift: What It Is and How to Eliminate It
You are reading an article on your phone. You are about to tap a link. Then the page jumps: an image loads above the text, a banner slides in, a font swaps and the paragraph you were reading is suddenly somewhere else entirely. You accidentally tap an ad you never intended to click. That frustrating experience has a name: Cumulative Layout Shift.
CLS is one of Google’s three Core Web Vitals, and it directly affects both your search rankings and your users’ experience. Unlike other performance metrics that deal with speed, CLS measures visual stability: how much unexpected movement happens on a page as it loads and as users interact with it. We go deeper on all of this in our long form guide to website performance.
We fix CLS issues on client sites regularly, and the causes are almost always the same handful of problems. The good news is that every one of them has a straightforward fix once you know what to look for.
CLS in Plain English
Cumulative Layout Shift measures the total amount of unexpected layout movement that happens during a page’s entire lifespan. Every time a visible element shifts position without the user initiating it, that movement gets scored. The scores for all individual shifts are added up to produce the final CLS value.
A shift only counts as unexpected if the user did not cause it. Clicking a button that expands an accordion section does not count. But an image loading late and pushing content down absolutely does count.
What Counts as a Good Score
Google uses these thresholds:
Most sites we audit for the first time land somewhere between 0.15 and 0.5. That means they are actively hurting their user experience and their search rankings. The target is always 0.1 or below.
Why CLS Matters for Rankings
In 2021, Google officially incorporated Core Web Vitals (including CLS) into its ranking algorithm. While content relevance and backlinks still carry more weight, CLS acts as a tiebreaker and a trust signal. When two pages offer similar content and authority, the one with better Core Web Vitals will rank higher.
Beyond rankings, poor CLS directly impacts conversions. Users who experience layout shifts are more likely to bounce, less likely to complete forms, and far less likely to trust your site enough to make a purchase. One study found that publishers who improved their CLS scores saw a 15 percent reduction in bounce rates.

How to Measure CLS
You need both lab data and field data to get a complete picture.
PageSpeed Insights
Go to pagespeed.web.dev and enter your URL. The tool will show your CLS score under Core Web Vitals, along with specific diagnostics that identify which elements are shifting. The field data section shows real-world CLS scores from actual Chrome users over the past 28 days. The lab data section shows what the tool measured during its test run.
Chrome DevTools
Open DevTools, go to the Performance tab, and check “Web Vitals.” Record a page load, and the timeline will highlight layout shifts with pink markers. Click on any shift to see exactly which elements moved and by how much. This is invaluable for debugging specific issues.
Web Vitals Extension
Install the Web Vitals Chrome extension for a quick, real-time readout of CLS (and the other Core Web Vitals) as you browse your site. It updates live, so you can see shifts happening in real time as you scroll and interact.
Google Search Console
The Core Web Vitals report in Search Console shows which pages on your site have CLS issues based on real user data. This is the best tool for identifying problems at scale across your entire site.
The Most Common Causes and Their Fixes
Images Without Dimensions
This is the single most common cause of CLS on the web. When an image tag does not include width and height attributes, the browser does not know how much space to reserve for it. The browser starts rendering the page, the image loads a moment later, and everything below it gets pushed down.
The fix: Always include width and height attributes on image elements.
<!-- Bad: No dimensions, causes layout shift -->
<img src="hero-photo.jpg" alt="Office building exterior">
<!-- Good: Dimensions tell the browser to reserve space -->
<img src="hero-photo.jpg" alt="Office building exterior" width="1200" height="800">For responsive images, combine explicit dimensions with CSS:
img {
max-width: 100%;
height: auto;
}The browser uses the width and height attributes to calculate the aspect ratio, reserves the correct amount of vertical space, and the image fills that space when it loads. Zero layout shift.
Modern CSS also supports the aspect-ratio property, which achieves the same goal:
.hero-image {
aspect-ratio: 3 / 2;
width: 100%;
object-fit: cover;
}Web Fonts Causing Reflow
When a custom web font loads, it replaces the fallback system font. If the two fonts have different character widths, line heights, or spacing, the text reflows and everything around it shifts. This is called Flash of Unstyled Text (FOUT) or Flash of Invisible Text (FOIT), and both cause CLS.
The fix: Use font-display: swap combined with a well-matched fallback font.
@font-face {
font-family: 'Brand Font';
src: url('/fonts/brand-font.woff2') format('woff2');
font-display: swap;
}Then match your fallback font’s metrics as closely as possible to your custom font:
body {
font-family: 'Brand Font', Arial, sans-serif;
}For even better results, use the CSS size-adjust, ascent-override, descent-override, and line-gap-override descriptors to fine-tune the fallback font metrics:
@font-face {
font-family: 'Brand Font Fallback';
src: local('Arial');
size-adjust: 105%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
body {
font-family: 'Brand Font', 'Brand Font Fallback', sans-serif;
}Also, preload your most critical font files so they arrive as early as possible:
<link rel="preload" href="/fonts/brand-font.woff2" as="font" type="font/woff2" crossorigin>Dynamically Injected Content
Content that gets inserted into the page after initial render (cookie consent banners, notification bars, promotional banners, chat widgets, newsletter popups) pushes existing content around and causes layout shifts.
The fix: Reserve space for dynamic content before it loads.
For top-of-page banners, use a CSS min-height on the container:
.cookie-banner-container {
min-height: 60px;
}For chat widgets and floating elements, use fixed or sticky positioning so they overlay content rather than pushing it:
.chat-widget {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 1000;
}For content that loads based on an API response (like a promotional banner that may or may not appear), reserve the space with a placeholder:
.promo-banner-slot {
min-height: 80px;
contain: layout;
}The contain: layout property tells the browser that changes inside this element should not affect the layout of elements outside it.
Ads and Embeds Without Reserved Space
Third-party ads, embedded videos, iframes, and social media embeds are notorious CLS offenders. They load asynchronously and often inject content with unpredictable dimensions.
The fix: Always wrap embeds in a container with predefined dimensions.
<div class="video-embed" style="aspect-ratio: 16 / 9; width: 100%;">
<iframe src="https://www.youtube.com/embed/VIDEO_ID"
width="100%" height="100%"
style="position: absolute; inset: 0;"
loading="lazy">
</iframe>
</div>For ad slots, define the exact dimensions the ad network will fill:
.ad-slot-leaderboard {
min-height: 90px;
width: 728px;
max-width: 100%;
background-color: #f0f0f0; /* Placeholder color */
}If an ad slot might remain empty, use the collapse behavior carefully. It is better to show a subtle placeholder than to have the page jump when the ad either loads or fails to load.
Late-Loading JavaScript That Modifies the DOM
JavaScript that runs after the page has rendered and modifies visible elements (adding classes, changing text, inserting nodes) causes layout shifts. This is common with A/B testing tools, personalization scripts, and poorly implemented lazy loading.
The fix: Move critical DOM modifications to server-side rendering or execute them before the page becomes visible.
For A/B testing tools, use server-side implementations or apply changes during the <head> before any content renders, rather than after page load. If you must use client-side A/B testing, hide the affected content until the modification is applied:
.ab-test-container {
opacity: 0;
transition: opacity 0.2s;
}
.ab-test-container.ready {
opacity: 1;
}This trades a brief invisible period for zero layout shift, a worthwhile tradeoff.
CSS Animations That Trigger Layout
Animating properties like width, height, top, left, margin, or padding forces the browser to recalculate layout, which can cause shifts. Stick to transform and opacity for animations: they are handled by the compositor and do not affect layout.
/* Bad: Animates height, triggers layout shift */
.dropdown {
transition: height 0.3s ease;
}
/* Good: Animates transform, no layout shift */
.dropdown {
transition: transform 0.3s ease;
transform-origin: top;
transform: scaleY(0);
}
.dropdown.open {
transform: scaleY(1);
}A Systematic Approach to Fixing CLS
Do not try to fix everything at once. Follow this process:
- Measure your current score. Use PageSpeed Insights and Search Console to identify which pages have the worst CLS.
- Identify the largest shifts. Use Chrome DevTools Performance recording to pinpoint exactly which elements are shifting and when.
- Fix the biggest offenders first. Usually images without dimensions and font loading account for the majority of CLS on most sites.
- Test after each fix. Re-run PageSpeed Insights after deploying changes to confirm improvement.
- Monitor field data. Lab scores improve immediately, but field data in Search Console takes 28 days to reflect changes since it is based on real user metrics.
CLS Pitfalls That Catch Developers Off Guard
- Lazy-loaded images above the fold. If your lazy loading library does not reserve space before the image enters the viewport, the swap from placeholder to image causes a shift. Only lazy load images below the fold, and always use dimension attributes.
- Responsive design breakpoints. An element that has no CLS issues on desktop might shift significantly on mobile. Test at multiple viewport widths.
- Third-party scripts you do not control. Analytics tags, live chat, review widgets, and social sharing buttons can all inject content that causes shifts. Audit every third-party script on your site.
- Skeleton screens done wrong. Skeleton loading screens are meant to prevent CLS, but if the skeleton does not match the final content’s dimensions exactly, the swap itself causes a shift.
Fixing CLS Is Not Optional
Google is measuring it. Users are experiencing it. And your competitors who fix it will outrank you in local search and convert visitors at a higher rate. CLS is one of the most fixable performance issues on the web. Most sites can get under the 0.1 threshold with a few hours of focused development work.
A stable, fast page was a core requirement when we rebuilt Hot Dog Business Growth’s consulting site. The full breakdown is in the case study.