How to Fix Cumulative Layout Shift Issues on Mobile Devices

If you’ve opened Chrome DevTools on a mobile emulator and watched your CLS score balloon past 0.25, you already know that mobile layout shifts are a different beast than desktop ones. Narrow viewports, slower connections, and injected third-party content combine to make Cumulative Layout Shift the trickiest Core Web Vital to tame on phones.

This guide skips the generic advice and walks you through the actual causes we see on real mobile pages, with copy-paste fixes for each one. If you’re troubleshooting a specific issue, jump straight to the section that matches your problem.

Quick Diagnosis: Where Is Your Mobile CLS Coming From?

Before touching any code, identify the shifting element. In Chrome DevTools:

  1. Open the Performance panel and toggle mobile emulation (Slow 4G, 4x CPU throttling).
  2. Record a page load and look for the Layout Shifts track in red.
  3. Click any shift block to see the exact elements that moved and their shift score.

You can also use the Web Vitals extension or run this snippet in the console to log shifts in real time:

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

Once you know which element is shifting, match it against the causes below.

mobile phone website loading

1. Unsized Images and Videos

This is still the number one cause of mobile CLS in 2026. When the browser doesn’t know an image’s dimensions, it renders zero height until the file downloads, then pushes everything below it downward.

The Fix: Always Set Width and Height

Modern browsers use the width and height attributes to calculate an aspect ratio and reserve space before the image loads:

<img src="hero-mobile.webp" 
     width="800" 
     height="600" 
     alt="Hero image"
     style="max-width: 100%; height: auto;">

The inline style keeps the image responsive while the attributes preserve the aspect ratio. Do not omit the attributes and rely on CSS alone.

For Responsive Art Direction

If you serve different images per breakpoint, use CSS aspect-ratio to lock the box:

.hero-image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

For Videos and Iframes

<div style="aspect-ratio: 16/9; width: 100%;">
  <iframe src="https://player.example.com/video" 
          style="width:100%; height:100%; border:0;"></iframe>
</div>

2. Web Fonts Causing FOUT and FOIT

On mobile, custom fonts often load after first paint. When the swap happens, line heights and character widths change, shifting entire paragraphs. This is especially painful with heading fonts.

The Fix: Preload and Use size-adjust

Step 1: preload your critical font files.

<link rel="preload" 
      href="/fonts/inter-var.woff2" 
      as="font" 
      type="font/woff2" 
      crossorigin>

Step 2: use font-display: swap combined with a fallback that matches your web font’s metrics via size-adjust, ascent-override, and descent-override:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2-variations');
  font-display: swap;
}

@font-face {
  font-family: 'Inter-fallback';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
}

body {
  font-family: 'Inter', 'Inter-fallback', sans-serif;
}

Tools like the Fontsource metric override generator can calculate the exact percentages for your custom font.

mobile phone website loading

3. Injected Ads, Embeds, and Third-Party Widgets

Ad slots that resize after loading are catastrophic on mobile because the viewport is narrow, so any injected banner pushes a huge percentage of visible content. Same story for cookie banners, chat widgets, and social embeds.

The Fix: Reserve Space With Min-Height

Always reserve the maximum expected size for the ad slot:

.ad-slot-mobile {
  min-height: 250px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #f5f5f5;
}

If the ad ends up smaller, you’ll have empty space, but no shift. That’s the trade-off Google rewards.

Cookie Banners: Overlay, Don’t Push

Never insert a cookie banner at the top of the DOM. Use position: fixed at the bottom of the viewport:

.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 9999;
}

4. Dynamically Injected Content Above the Fold

Notifications, promo bars, “free shipping” strips, or A/B test variants that inject after hydration push everything downward. On mobile this often triggers shifts of 0.15 or more from a single element.

The Fix: Server-Side Render or Reserve Space

If the promo bar is conditional, decide server-side and render the placeholder either way:

<div class="promo-slot" style="min-height: 40px;">
  <!-- Injected client-side, but space is reserved -->
</div>

For A/B tests, use CSS variants instead of DOM injection whenever possible. If you must inject, do it before first paint using a synchronous script in the <head>.

mobile phone website loading

5. Hamburger Menus and Mobile Navigation

A common mobile-specific issue: the mobile menu is rendered as a full-width block by default, then JavaScript kicks in and hides it. Between DOM ready and JS execution, the menu occupies space and pushes the hero down.

The Fix: Hide With CSS, Not JavaScript

@media (max-width: 768px) {
  .mobile-menu {
    display: none;
  }
  .mobile-menu.is-open {
    display: block;
  }
}

The menu is hidden immediately by the CSS parser, before JavaScript executes.

6. Lazy-Loaded Content Without Placeholders

Native lazy loading (loading="lazy") is great, but only if dimensions are set. For components lazy-loaded by JavaScript (product cards, comment sections, related posts), you need skeleton placeholders.

.product-card-skeleton {
  min-height: 320px;
  background: linear-gradient(90deg, #eee 25%, #f5f5f5 50%, #eee 75%);
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
}
mobile phone website loading

Mobile CLS Causes and Fixes Summary

Cause Primary Fix Impact
Unsized images width/height attributes + aspect-ratio High
Web fonts Preload + size-adjust fallback Medium
Ads and embeds min-height on slot container High
Dynamic content injection SSR or reserved placeholder High
Hamburger menu flash Hide via CSS media query Medium
Lazy-loaded components Skeleton placeholders Medium

Testing Your Fixes on Real Mobile Conditions

After applying fixes, don’t just check Lighthouse scores. Verify in these three places:

  • PageSpeed Insights: check the Mobile tab specifically, and look at field data (CrUX) not just lab data.
  • Chrome DevTools: throttle to Slow 4G and 4x CPU, then reload with cache disabled.
  • Search Console Core Web Vitals report: this is what Google actually uses for ranking. Give it 28 days to reflect changes.

Aim for a mobile CLS score below 0.1. Between 0.1 and 0.25 needs improvement, and above 0.25 is considered poor.

FAQ

What is a good CLS score on mobile in 2026?

The threshold remains 0.1 or lower for a “Good” rating. Between 0.1 and 0.25 needs improvement. Above 0.25 is poor and will hurt your rankings.

Why is my mobile CLS worse than desktop CLS?

Mobile viewports are narrow, so any shift affects a larger percentage of the visible area. Add slower connections and CPU throttling and shifts become both more frequent and more severe.

Does lazy loading cause CLS?

Only if you lazy load without reserving space. Native loading="lazy" combined with width and height attributes is safe. JavaScript-based lazy loading requires skeleton placeholders.

Can CSS transforms cause layout shift?

No. transform and opacity animations do not trigger layout shifts because they run on the compositor thread. Use them instead of animating top, left, width, or height.

How long does it take for CLS fixes to reflect in Search Console?

The Core Web Vitals report uses a 28-day rolling window of field data, so expect changes to appear gradually over roughly a month after deployment.

Should I use the content-visibility property to fix CLS?

Only with caution. content-visibility: auto improves rendering performance but can introduce shifts if you don’t set contain-intrinsic-size. Always pair them together.

Search

Recent Blog

  • All Post
  • Email Marketing
  • Responsive Website
  • SEO
  • Social Media Marketing
  • Web Design
  • Web Development

Subscribe

You have been successfully Subscribed! Ops! Something went wrong, please try again.

Company Name

Gemini Web

Company Address

3444 Hall Valley Drive, Davy, WV 24828 USA

Company Email

[email protected]

Copyright © 2022 Gemini Web. All Rights Reserved.