Webflow CLS Optimization | Blue Frog Docs

Webflow CLS Optimization

Fix Cumulative Layout Shift issues on Webflow websites to improve Core Web Vitals and user experience.

Webflow CLS Optimization

Cumulative Layout Shift (CLS) measures visual stability by tracking unexpected layout shifts during page load. This guide provides Webflow-specific solutions to eliminate layout shifts and improve your Core Web Vitals scores.

What is CLS?

Cumulative Layout Shift (CLS) is one of Google's Core Web Vitals that measures visual stability. It quantifies how much visible content shifts unexpectedly during the page lifecycle.

CLS Thresholds

  • Good: ≤ 0.1
  • Needs Improvement: 0.1 - 0.25
  • Poor: > 0.25

Common Causes of CLS in Webflow

  • Images without explicit dimensions
  • Webflow interactions and animations
  • Lazy-loaded content
  • Web fonts causing text reflow
  • Dynamic content injection
  • Ads and embeds loading late
  • CMS content without reserved space

Diagnosing CLS Issues in Webflow

Step 1: Identify Layout Shifts

Use Chrome DevTools to visualize shifts:

  1. Open your site in Chrome
  2. Press Ctrl+Shift+P (Windows) or Cmd+Shift+P (Mac)
  3. Type "Show Rendering"
  4. Enable Layout Shift Regions
  5. Reload your page
  6. Blue highlights show where shifts occur

Step 2: Measure CLS Score

Test your site's current CLS:

Step 3: Use DevTools Performance Tab

Detailed shift analysis:

  1. Open Chrome DevTools (F12)
  2. Go to Performance tab
  3. Check Web Vitals option
  4. Click Record and reload
  5. Click Stop recording
  6. Look for Layout Shift events in timeline
  7. Click each shift to see which elements moved

Webflow-Specific CLS Optimizations

1. Images Without Dimensions

Problem: Images without explicit width/height cause shifts as they load.

Set Image Dimensions in Webflow

For static images:

  1. Select the image in Webflow Designer
  2. Go to Style panel
  3. Set Width and Height explicitly
  4. Or use aspect-ratio to maintain proportions

Best practice: Always set dimensions or aspect ratios:

/* In Webflow Style panel or Custom Code */
.hero-image {
  width: 100%;
  aspect-ratio: 16 / 9;
}

Use Webflow's Responsive Image System

Webflow automatically generates responsive images, but ensure proper sizing:

  1. Upload images at 2x the display size
  2. Set width in Webflow Designer
  3. Webflow serves appropriate size for each device
  4. Height is calculated automatically from aspect ratio

Reserve Space for CMS Images

In CMS Collection templates:

  1. Select the image element
  2. Set a minimum height or aspect ratio
  3. This reserves space even before CMS image loads

Example custom code for CMS images:

.cms-image {
  aspect-ratio: 4 / 3;
  width: 100%;
  object-fit: cover;
}

2. Webflow Interactions Causing Shifts

Problem: Interactions that change element dimensions or position cause layout shifts.

Avoid Height/Width Animations

Bad: Animating from height: 0 to height: auto

Initial state: height: 0
On load: Animate to height: auto

This causes elements below to shift down.

Good: Use transform instead:

Initial state: transform: scaleY(0)
On load: Animate to transform: scaleY(1)

Transforms don't affect layout.

Use Transform and Opacity Only

Safe animation properties that don't cause CLS:

  • transform (translate, scale, rotate)
  • opacity
  • width, height
  • top, left, margin, padding
  • font-size

Delay Non-Critical Interactions

Move interactions to fire after page stability:

  1. Select element with interaction
  2. Go to Interactions panel
  3. Change trigger from Page Load to Page Load (After Delay)
  4. Set delay to 1000ms or more

Reserve Space for Animated Elements

If an element expands on interaction:

  1. Set a min-height in initial state
  2. This reserves space before animation
  3. Element expands within reserved space

3. Web Fonts Causing Text Shifts

Problem: Custom fonts loading late cause text to reflow.

Use font-display: swap

Add to Project Settings > Custom Code > Head Code:

<style>
  @font-face {
    font-family: 'Your Custom Font';
    src: url('font-url.woff2');
    font-display: swap; /* Show fallback font immediately, swap when loaded */
  }
</style>

For Google Fonts:

<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">

Note the display=swap parameter.

Match Fallback Font Metrics

Reduce shift by using similar fallback fonts:

body {
  font-family: 'Your Custom Font', Arial, sans-serif;
}

Or use size-adjust to match metrics:

@font-face {
  font-family: 'Fallback Font';
  src: local('Arial');
  size-adjust: 110%; /* Adjust to match custom font */
}

Preload Critical Fonts

In Head Code:

<link rel="preload" as="font" type="font/woff2" href="YOUR_FONT_URL.woff2" crossorigin>

4. Lazy Loading and Dynamic Content

Problem: Content loading after page render shifts existing content.

Don't Lazy Load Above-Fold Images

For hero and above-fold images:

  1. Select the image in Webflow
  2. Do NOT enable lazy loading
  3. Set explicit dimensions
  4. Browsers prioritize loading these images

Reserve Space for Lazy Loaded Content

For below-fold lazy loaded images:

  1. Set aspect-ratio or min-height
  2. Use skeleton screens or placeholders
  3. Content loads into reserved space without shifts

Example:

.lazy-image {
  aspect-ratio: 16 / 9;
  background: #f0f0f0; /* Placeholder color */
}

CMS Collection Lists

For dynamic CMS content:

  1. Set min-height on collection list items
  2. Use fixed aspect ratios for CMS images
  3. Reserve space for text content

5. Webflow Animations on Page Load

Problem: Opacity and slide-in animations that affect layout.

Remove Animations from Above-Fold

For hero sections and above-fold content:

  1. Avoid fade-in animations (opacity: 0 to opacity: 1)
  2. Remove slide-in animations that shift content
  3. Keep above-fold content static and visible immediately

Use CSS Contains

For animated sections, use CSS containment:

.animated-section {
  contain: layout;
}

This prevents the section from affecting surrounding layout.

Optimize Webflow IX2

Webflow's Interactions 2.0 (IX2) can cause shifts:

  1. Limit simultaneous animations: Reduce complexity
  2. Use transform-only animations: Avoid layout-affecting properties
  3. Test on mobile: Interactions can behave differently on mobile
  4. Disable on slow connections: Use media queries to disable on slow networks

6. Webflow Navbar and Headers

Problem: Fixed or sticky navbars causing shifts.

Reserve Space for Fixed Headers

When using fixed position navbars:

  1. Set explicit height on navbar
  2. Add matching padding to body or main content
  3. Prevents content jumping when navbar becomes fixed

Example in Custom Code > Head Code:

<style>
  .navbar {
    height: 80px; /* Fixed height */
  }

  body {
    padding-top: 80px; /* Match navbar height */
  }
</style>

Avoid Changing Navbar Height

Don't animate navbar height on scroll:

  • ✗ Shrinking navbar on scroll (height change)
  • ✓ Changing background color on scroll (no layout change)

7. Third-Party Embeds and Ads

Problem: Ads, videos, and embeds loading without reserved space.

Reserve Space for YouTube/Vimeo Embeds

Use aspect-ratio for video embeds:

  1. Wrap embed in a div
  2. Set aspect ratio on container

In Webflow:

.video-container {
  position: relative;
  aspect-ratio: 16 / 9;
  width: 100%;
}

.video-container iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

Ads and Marketing Pixels

Reserve space for ad slots:

.ad-slot {
  min-height: 250px; /* Reserve space for ad */
  width: 300px;
}

Social Media Embeds

Social embeds (Twitter, Instagram) load asynchronously:

  1. Set minimum height on embed container
  2. Use placeholders or skeleton screens
  3. Load embeds on user interaction (click to load)

8. Webflow CMS Dynamic Content

Problem: CMS content loading causes shifts.

Set Minimum Heights for CMS Elements

In your CMS Collection template:

.cms-rich-text {
  min-height: 300px; /* Approximate content height */
}

.cms-image {
  aspect-ratio: 4 / 3;
}

Use Skeleton Screens

Show placeholders while CMS content loads:

  1. Create a loading state in Webflow
  2. Show gray boxes matching content dimensions
  3. Replace with actual content when loaded

Preload CMS Images

In Collection Page template:

<link rel="preload" as="image" href="CMS_IMAGE_URL">

Use Webflow's "Insert field" to get CMS image URL.

Advanced Webflow CLS Fixes

1. Critical CSS for Above-Fold

Inline critical CSS in Head Code to prevent font/layout shifts:

<style>
  /* Critical above-fold styles */
  .hero {
    min-height: 100vh;
    display: flex;
    align-items: center;
  }

  .hero-heading {
    font-size: 3rem;
    line-height: 1.2;
    /* Use fallback font metrics initially */
  }
</style>

2. Implement Skeleton Screens

Create loading states in Webflow:

  1. Design skeleton layout (gray boxes)
  2. Show by default
  3. Hide when content loads
  4. Maintains layout during load

Example structure:

<div class="skeleton-loader">
  <div class="skeleton-text"></div>
  <div class="skeleton-text"></div>
  <div class="skeleton-image"></div>
</div>

CSS:

.skeleton-text {
  height: 20px;
  background: #e0e0e0;
  margin-bottom: 10px;
  border-radius: 4px;
}

.skeleton-image {
  aspect-ratio: 16 / 9;
  background: #e0e0e0;
  border-radius: 4px;
}

Cookie consent banners can cause shifts:

Bad: Banner pushes content down when it appears

Good: Fixed position banner overlays content

.cookie-banner {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  /* Overlays content, doesn't shift it */
}

4. Monitor CLS with JavaScript

Track CLS in production:

<!-- Add to Project Settings > Custom Code > Footer Code -->
<script>
  let clsValue = 0;
  let clsEntries = [];

  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (!entry.hadRecentInput) {
        clsValue += entry.value;
        clsEntries.push(entry);

        // Log shift details
        console.log('Layout Shift:', {
          value: entry.value,
          sources: entry.sources
        });
      }
    }
  });

  observer.observe({ type: 'layout-shift', buffered: true });

  // Send to analytics on page unload
  window.addEventListener('beforeunload', () => {
    if (typeof gtag !== 'undefined') {
      gtag('event', 'CLS', {
        'value': Math.round(clsValue * 1000),
        'event_category': 'Web Vitals',
        'non_interaction': true
      });
    }
  });
</script>

Mobile-Specific CLS Fixes

Mobile often has worse CLS than desktop.

1. Simplify Mobile Animations

Reduce interactions on mobile breakpoints:

  1. Switch to Mobile Portrait breakpoint in Webflow
  2. Disable complex interactions
  3. Remove layout-affecting animations
  4. Keep mobile designs simple and static

2. Mobile Font Sizes

Avoid large font-size differences that cause reflow:

/* Avoid */
.heading {
  font-size: 4rem; /* Desktop */
}

@media (max-width: 767px) {
  .heading {
    font-size: 2rem; /* Large shift on mobile */
  }
}

3. Mobile Image Optimization

Use mobile-specific images:

  1. Set desktop image in default view
  2. Switch to mobile breakpoint
  3. Upload smaller mobile image
  4. Maintains aspect ratio, different source

Testing CLS Improvements

Before and After Comparison

  1. Baseline: Test current CLS with PageSpeed Insights
  2. Identify shifts: Use Chrome DevTools Layout Shift Regions
  3. Implement fixes: Apply optimizations from this guide
  4. Publish changes: Publish your Webflow site
  5. Wait for CDN: Wait 5-10 minutes for CDN propagation
  6. Retest: Run PageSpeed Insights again
  7. Compare scores: Verify CLS improvement

Testing Checklist

  • All images have explicit dimensions or aspect ratios
  • No layout-affecting interactions above-fold
  • Fonts use font-display: swap
  • Fixed/sticky headers have reserved space
  • Embeds and videos have aspect ratios
  • CMS content has min-heights
  • No cookie banners shifting content
  • Mobile breakpoints tested separately

Common Webflow CLS Issues and Fixes

Issue: Hero Section Shifting on Load

Cause: Hero background image or heading causing shift.

Fix:

  1. Set fixed height on hero section
  2. Remove fade-in animations
  3. Set explicit dimensions on hero image
  4. Use transform instead of opacity

Issue: Navbar Height Changing

Cause: Sticky navbar shrinking on scroll.

Fix:

  1. Keep navbar height consistent
  2. Use transform to "hide" parts instead
  3. Or accept navbar change as user-initiated (not counted in CLS)

Issue: CMS Images Shifting

Cause: CMS images loading without dimensions.

Fix:

  1. Set aspect-ratio on CMS image element
  2. Use Webflow's image field (not HTML embed)
  3. Set minimum dimensions in CMS template

Issue: Webflow Interactions Causing Shifts

Cause: IX2 animations affecting layout.

Fix:

  1. Use transform and opacity only
  2. Delay interactions until after page load
  3. Remove animations from above-fold content

Issue: Web Fonts Loading Late

Cause: FOUT (Flash of Unstyled Text) causing reflow.

Fix:

  1. Add font-display: swap to font declarations
  2. Preload critical fonts
  3. Use fallback fonts with similar metrics

Monitoring CLS Over Time

Track CLS with GA4:

<script>
  let clsValue = 0;

  const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
      if (!entry.hadRecentInput) {
        clsValue += entry.value;
      }
    }
  });

  observer.observe({ type: 'layout-shift', buffered: true });

  window.addEventListener('beforeunload', () => {
    gtag('event', 'web_vitals', {
      'metric_name': 'CLS',
      'metric_value': Math.round(clsValue * 1000),
      'page_path': window.location.pathname
    });
  });
</script>

Next Steps

Additional Resources

// SYS.FOOTER