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:
- Open your site in Chrome
- Press Ctrl+Shift+P (Windows) or Cmd+Shift+P (Mac)
- Type "Show Rendering"
- Enable Layout Shift Regions
- Reload your page
- Blue highlights show where shifts occur
Step 2: Measure CLS Score
Test your site's current CLS:
- Google PageSpeed Insights: Mobile and desktop CLS scores
- Chrome DevTools Lighthouse: Built-in audit
- Web Vitals Extension: Real-time CLS monitoring
Step 3: Use DevTools Performance Tab
Detailed shift analysis:
- Open Chrome DevTools (F12)
- Go to Performance tab
- Check Web Vitals option
- Click Record and reload
- Click Stop recording
- Look for Layout Shift events in timeline
- 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:
- Select the image in Webflow Designer
- Go to Style panel
- Set Width and Height explicitly
- 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:
- Upload images at 2x the display size
- Set width in Webflow Designer
- Webflow serves appropriate size for each device
- Height is calculated automatically from aspect ratio
Reserve Space for CMS Images
In CMS Collection templates:
- Select the image element
- Set a minimum height or aspect ratio
- 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:
- Select element with interaction
- Go to Interactions panel
- Change trigger from Page Load to Page Load (After Delay)
- Set delay to 1000ms or more
Reserve Space for Animated Elements
If an element expands on interaction:
- Set a min-height in initial state
- This reserves space before animation
- 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:
- Select the image in Webflow
- Do NOT enable lazy loading
- Set explicit dimensions
- Browsers prioritize loading these images
Reserve Space for Lazy Loaded Content
For below-fold lazy loaded images:
- Set aspect-ratio or min-height
- Use skeleton screens or placeholders
- 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:
- Set min-height on collection list items
- Use fixed aspect ratios for CMS images
- 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:
- Avoid fade-in animations (
opacity: 0toopacity: 1) - Remove slide-in animations that shift content
- 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:
- Limit simultaneous animations: Reduce complexity
- Use transform-only animations: Avoid layout-affecting properties
- Test on mobile: Interactions can behave differently on mobile
- 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:
- Set explicit height on navbar
- Add matching padding to body or main content
- 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:
- Wrap embed in a div
- 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:
- Set minimum height on embed container
- Use placeholders or skeleton screens
- 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:
- Create a loading state in Webflow
- Show gray boxes matching content dimensions
- 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:
- Design skeleton layout (gray boxes)
- Show by default
- Hide when content loads
- 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;
}
3. Avoid Cookie Banners That Shift Content
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:
- Switch to Mobile Portrait breakpoint in Webflow
- Disable complex interactions
- Remove layout-affecting animations
- 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:
- Set desktop image in default view
- Switch to mobile breakpoint
- Upload smaller mobile image
- Maintains aspect ratio, different source
Testing CLS Improvements
Before and After Comparison
- Baseline: Test current CLS with PageSpeed Insights
- Identify shifts: Use Chrome DevTools Layout Shift Regions
- Implement fixes: Apply optimizations from this guide
- Publish changes: Publish your Webflow site
- Wait for CDN: Wait 5-10 minutes for CDN propagation
- Retest: Run PageSpeed Insights again
- 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:
- Set fixed height on hero section
- Remove fade-in animations
- Set explicit dimensions on hero image
- Use transform instead of opacity
Issue: Navbar Height Changing
Cause: Sticky navbar shrinking on scroll.
Fix:
- Keep navbar height consistent
- Use transform to "hide" parts instead
- Or accept navbar change as user-initiated (not counted in CLS)
Issue: CMS Images Shifting
Cause: CMS images loading without dimensions.
Fix:
- Set aspect-ratio on CMS image element
- Use Webflow's image field (not HTML embed)
- Set minimum dimensions in CMS template
Issue: Webflow Interactions Causing Shifts
Cause: IX2 animations affecting layout.
Fix:
- Use transform and opacity only
- Delay interactions until after page load
- Remove animations from above-fold content
Issue: Web Fonts Loading Late
Cause: FOUT (Flash of Unstyled Text) causing reflow.
Fix:
- Add
font-display: swapto font declarations - Preload critical fonts
- 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
- Optimize LCP for loading performance
- Fix Tracking Issues if analytics aren't working
- Troubleshooting Overview for other common issues