Cumulative Layout Shift (CLS)

What is Cumulative Layout Shift (CLS)?

Cumulative Layout Shift (CLS) is one of Google's three SEO Metrics metrics and measures the visual stability of a web page. CLS quantifies how often unexpected layout shifts occur during the entire lifecycle of a page.

Definition and Importance

CLS measures the sum of all layout shifts that are not caused by user interactions. These shifts occur when visible elements change their position after they have already been rendered.

Key Metrics:

  • Good: CLS ≤ 0.1
  • Needs Improvement: 0.1 < CLS ≤ 0.25
  • Poor: CLS > 0.25

How is CLS calculated?

Calculation Formula

CLS is calculated using the following formula:

CLS = Σ (Shift Area × Distance Fraction)

Impact Fraction: Proportion of the viewport affected by the layout shift
Distance Fraction: Largest distance an element was shifted (relative to viewport size)

Measurement Timing

CLS is measured throughout the entire lifetime of a page, not just on initial load. This includes:

  • Initial loading
  • Dynamic content
  • User interactions
  • Asynchronous resources

Common Causes of Layout Shifts

1. Images without Dimensions

Problem: Images are loaded without fixed width and height, causing the layout to jump when the image loads.

Solution:

<!-- Bad -->
<img src="image.jpg" alt="Description">

<!-- Good -->
<img src="image.jpg" alt="Description" width="800" height="600">

2. Dynamically Inserted Content

Problem: Content is added after initial loading and shifts existing elements.

Examples:

  • Ad banners
  • Social media widgets
  • Comments
  • Recommendations

3. External Fonts without Fallback

Problem: Web fonts are loaded asynchronously and replace fallback fonts, causing text sizes and spacing to change.

Solution:

@font-face {
  font-family: 'Custom Font';
  font-display: swap; /* Prevents FOIT */
  src: url('font.woff2') format('woff2');
}

4. Asynchronous Scripts

Problem: JavaScript loads content asynchronously and shifts the layout in the process.

Examples:

  • Analytics tracking
  • Chat widgets
  • Cookie banners

CLS Optimization Strategies

1. Optimize Images

Reserved space for images:

<div class="image-container" style="aspect-ratio: 16/9;">
  <img src="image.jpg" alt="Description" loading="lazy">
</div>

CSS Solution:

.image-container {
  width: 100%;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 Aspect Ratio */
  position: relative;
}

.image-container img {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

2. Optimize Web Fonts

Font-Display Strategies:

@font-face {
  font-family: 'Custom Font';
  font-display: swap; /* Faster text visibility */
  src: url('font.woff2') format('woff2');
}

/* Define fallback font */
body {
  font-family: 'Custom Font', Arial, sans-serif;
}

3. Prepare Dynamic Content

Reserved space for dynamic content:

<div class="content-area">
  <div class="placeholder" style="height: 200px;">
    <!-- Content will be inserted here -->
  </div>
</div>

4. Use CSS Transformations

Instead of layout changes:

/* Bad - causes layout shift */
.element {
  margin-top: 20px;
}

/* Good - uses transform */
.element {
  transform: translateY(20px);
}

CLS Measurement and Monitoring

Tools for CLS Measurement

Tool
Description
Data Source
Google PageSpeed Insights
Lab data for quick tests
Real-world data from Chrome User Experience Report
Google Search Console
Core Web Vitals report
Field data for real users
Chrome DevTools
Performance tab
Layout Shift Records
Web Vitals Extension
Real-time measurement
Immediate feedback

Using Chrome DevTools

Step-by-step guide:

  1. Open DevTools (F12)
  2. Select Performance tab
  3. Click Record button
  4. Load page and interact
  5. Press Stop
  6. Search for Layout Shifts in the timeline

Analyze Layout Shift Records:

  • Cumulative Score: Total CLS value
  • Sources: Cause of the shift
  • Nodes: Affected DOM elements

Best Practices for CLS Optimization

1. Define Dimensions for All Media

<!-- Images -->
<img src="image.jpg" width="800" height="600" alt="Description">

<!-- Videos -->
<video width="800" height="450" controls>
  <source src="video.mp4" type="video/mp4">
</video>

<!-- Iframes -->
<iframe src="embed.html" width="800" height="600"></iframe>

2. Use CSS Containers

.media-container {
  position: relative;
  width: 100%;
  height: 0;
  padding-bottom: 56.25%; /* 16:9 */
  overflow: hidden;
}

.media-container img,
.media-container video {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

3. Optimize Font Loading

<!-- Preload important fonts -->
<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>

<!-- Font display swap -->
<style>
@font-face {
  font-family: 'Custom Font';
  font-display: swap;
  src: url('font.woff2') format('woff2');
}
</style>

4. Prepare Dynamic Content

/* Placeholder for dynamic content */
.dynamic-content {
  min-height: 200px;
  background: #f5f5f5;
}

/* Skeleton Loading */
.skeleton {
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: loading 1.5s infinite;
}

@keyframes loading {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

CLS Debugging Techniques

1. Layout Shift Debugging

// Enable CLS measurement
new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    if (!entry.hadRecentInput) {
      console.log('Layout Shift:', entry.value);
      console.log('Sources:', entry.sources);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

2. Visual Debugging Tools

Chrome DevTools:

  • Rendering tab → Enable "Layout Shift Regions"
  • Performance tab → Analyze Layout Shift Records

Browser Extensions:

  • Web Vitals Extension
  • Lighthouse CI

3. Automated Tests

// Puppeteer/Playwright Test
const { chromium } = require('playwright');

async function measureCLS() {
  const browser = await chromium.launch();
  const page = await browser.newPage();
  
  await page.goto('https://example.com');
  
  const cls = await page.evaluate(() => {
    return new Promise((resolve) => {
      let clsValue = 0;
      new PerformanceObserver((list) => {
        for (const entry of list.getEntries()) {
          if (!entry.hadRecentInput) {
            clsValue += entry.value;
          }
        }
        resolve(clsValue);
      }).observe({type: 'layout-shift', buffered: true});
    });
  });
  
  console.log('CLS Score:', cls);
  await browser.close();
}

Common CLS Errors and Solutions

1. Cookie Banner without Reserved Space

Problem: Cookie banner appears suddenly and shifts content.

Solution:

/* Reserve space for cookie banner */
body {
  padding-bottom: 60px; /* Height of cookie banner */
}

.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 60px;
  transform: translateY(100%);
  transition: transform 0.3s ease;
}

.cookie-banner.show {
  transform: translateY(0);
}

2. Lazy Load without Dimensions

Problem: Lazy-loaded images shift layout when loading.

Solution:

<div class="image-wrapper" style="aspect-ratio: 16/9;">
  <img 
    src="placeholder.jpg" 
    data-src="real-image.jpg" 
    alt="Description"
    loading="lazy"
    class="lazy-image"
  >
</div>

3. Dynamic Advertising

Problem: Ad banners are loaded asynchronously and shift content.

Solution:

<!-- Reserved space for advertising -->
<div class="ad-container" style="height: 250px; background: #f0f0f0;">
  <div id="ad-slot"></div>
</div>

<script>
// Only load ad when container is visible
const adContainer = document.getElementById('ad-slot');
const observer = new IntersectionObserver((entries) => {
  if (entries[0].isIntersecting) {
    loadAd();
    observer.disconnect();
  }
});
observer.observe(adContainer);
</script>

CLS and SEO Impact

Ranking Factor since 2021

CLS has been an official Google ranking factor since May 2021 and is part of Core Web Vitals. Poor CLS values can lead to:

  • Ranking losses in search results
  • Reduced visibility in Google Search Console
  • Poor user experience and higher bounce rate
  • Loss of conversions and engagement

Mobile-Priority Indexing

Since Google uses mobile-first indexing, CLS is particularly important for:

  • Mobile performance and user experience
  • Mobile search rankings
  • Core Web Vitals on mobile devices

CLS Monitoring Strategies

1. Continuous Monitoring

Tools for continuous monitoring:

  • Google Search Console
  • PageSpeed Insights API
  • Custom analytics integration
  • Real User Monitoring (RUM)

2. Alerts and Notifications

// CLS alert system
function checkCLS() {
  new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (entry.value > 0.25) {
        // Send alert
        sendAlert('CLS Warning', `CLS: ${entry.value}`);
      }
    }
  }).observe({type: 'layout-shift', buffered: true});
}

3. A/B Testing for CLS

Test design for CLS optimization:

  • Variant A: Original layout
  • Variant B: Optimized layout with reserved spaces
  • Metrics: CLS, bounce rate, Goal Rate

Future of CLS Measurement

Extended CLS Metrics

Google is working on extended CLS metrics:

  • CLS 2.0: Improved measurement of layout shifts
  • Subframe CLS: Measurement in iframes
  • Windowed CLS: Measurement in specific time windows

New Optimization Possibilities

CSS Container Queries:

@container (min-width: 300px) {
  .content {
    font-size: 1.2rem;
  }
}

CSS Scroll Timeline:

@scroll-timeline scroll-timeline {
  source: selector(#scroll-container);
  orientation: vertical;
}

CLS Optimization Checklist

✅ Technical Checklist

  • [ ] All images have fixed dimensions
  • [ ] Web fonts use font-display: swap
  • [ ] Dynamic content has reserved space
  • [ ] CSS transformations instead of layout changes
  • [ ] Lazy loading with aspect ratio
  • [ ] Cookie banner without layout shift
  • [ ] Advertising with fixed dimensions

✅ Monitoring Checklist

  • [ ] Monitor Google Search Console
  • [ ] Test PageSpeed Insights regularly
  • [ ] Use Chrome DevTools Performance tab
  • [ ] Implement Real User Monitoring
  • [ ] Set up alerts for CLS thresholds

✅ Content Checklist

  • [ ] All media files optimized
  • [ ] Font loading strategy defined
  • [ ] Dynamic content prepared
  • [ ] Mobile-first approach implemented
  • [ ] User experience prioritized

Related Topics