Cumulative Layout Shift (CLS) measures visual stability. Layout shifts frustrate users and harm SEO. Zyro sites can experience CLS from images, fonts, and dynamic content.
Target: CLS under 0.1 Good: Under 0.1 | Needs Improvement: 0.1-0.25 | Poor: Over 0.25
For general CLS concepts, see the global CLS guide.
Zyro-Specific CLS Issues
1. Images Without Dimensions
Images loading without defined dimensions cause layout shifts.
Problem: Zyro templates may not always set explicit width/height.
Diagnosis:
- Run PageSpeed Insights
- Look for "Image elements do not have explicit width and height"
- Check CLS score in Core Web Vitals
Solutions:
A. Use Zyro's Image Elements
Zyro's built-in image elements automatically handle dimensions:
Best Practice:
- Use Zyro's image blocks (not custom HTML)
- Upload appropriately sized images
- Avoid manually overriding dimensions
B. Set Dimensions in Custom Code
If using custom HTML sections:
Bad (Causes CLS):
<img src="image.jpg" alt="Description">
Good (Prevents CLS):
<img src="image.jpg" width="800" height="600" alt="Description">
Best (Responsive with aspect ratio):
<img
src="image.jpg"
width="800"
height="600"
style="max-width: 100%; height: auto;"
alt="Description"
>
2. Font Loading Causing Shifts
Custom fonts loading can cause text to shift.
Problem: Flash of Unstyled Text (FOUT) or Flash of Invisible Text (FOIT).
Solutions:
A. Use Zyro's Built-in Fonts
Recommended:
- Zyro's fonts are pre-optimized
- No layout shift
- Better performance
B. Optimize Custom Fonts
If you must use custom fonts:
<!-- Add to Header Code -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=CustomFont&display=swap"
rel="stylesheet"
>
CSS with font-display:
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2');
font-display: swap; /* Prevents invisible text */
}
3. Dynamic Content Loading
Content that loads after initial render causes shifts.
Problem: Third-party widgets, ads, or dynamic elements.
Common Culprits:
- Social media embeds
- Advertisement placeholders
- Chat widgets
- Review widgets
- Content loaded via JavaScript
Solutions:
A. Reserve Space for Dynamic Content
<!-- Reserve space with min-height -->
<div style="min-height: 200px;">
<!-- Dynamic content loads here -->
</div>
B. Use Aspect Ratio Boxes
For embeds like YouTube videos:
<div style="position: relative; padding-bottom: 56.25%; height: 0;">
<iframe
src="https://www.youtube.com/embed/VIDEO_ID"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
frameborder="0"
allowfullscreen
></iframe>
</div>
C. Preload Critical Content
<!-- Add to Header Code -->
<link rel="preload" as="image" href="hero-image.jpg">
4. Ads and Banners
Advertising can cause significant CLS.
Problem: Ads load after page content, pushing content down.
Solutions:
Reserve Ad Space:
<div class="ad-container" style="min-height: 250px; background: #f0f0f0;">
<!-- Ad loads here -->
<div id="ad-slot"></div>
</div>
Sticky Elements: Ensure sticky elements have defined dimensions:
.sticky-header {
position: sticky;
top: 0;
height: 80px; /* Fixed height prevents shift */
}
5. Zyro Template Updates
Template changes can introduce CLS.
Problem: Zyro template updates modify layout.
Diagnosis:
- Compare CLS before/after template updates
- Check for new dynamic elements
- Review custom code compatibility
Solutions:
- Test CLS after template updates
- Reapply optimizations if needed
- Contact Zyro support for template issues
- Consider reverting to previous template version
6. Third-Party Widgets
Social media feeds, chat widgets, and embeds cause shifts.
Problem: Widgets load asynchronously without reserved space.
Common Widgets:
- Facebook page plugin
- Instagram feed
- Twitter timeline
- Live chat (Intercom, Drift)
- Review widgets (Trustpilot, Yelp)
Solutions:
A. Reserve Space for Widgets
<div style="min-height: 400px;">
<!-- Facebook page plugin loads here -->
<div class="fb-page" data-href="..."></div>
</div>
B. Load Below the Fold
Place widgets below the fold where CLS has less impact:
<!-- Place widgets in footer or below main content -->
C. Delay Widget Loading
<script>
window.addEventListener('load', function() {
setTimeout(function() {
// Load chat widget after initial render
loadChatWidget();
}, 2000);
});
</script>
7. Animations and Transitions
CSS animations can cause unexpected shifts.
Problem: Animations affecting layout instead of composition.
Bad (Causes CLS):
.element {
animation: slideIn 0.5s;
}
@keyframes slideIn {
from { height: 0; }
to { height: 200px; }
}
Good (No CLS):
.element {
animation: fadeIn 0.5s;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
Best Practices:
- Use
transformandopacityfor animations - Avoid animating
width,height,top,left - Use CSS
will-changefor performance
8. Mobile-Specific CLS
Mobile devices often have worse CLS.
Problem: Different layout on mobile, images sized incorrectly.
Solutions:
A. Test on Mobile Devices
- Use real mobile devices
- Use Chrome DevTools mobile emulation
- Check PageSpeed Insights mobile results
B. Responsive Images
<img
src="image.jpg"
srcset="
image-320w.jpg 320w,
image-640w.jpg 640w,
image-960w.jpg 960w
"
sizes="100vw"
width="960"
height="640"
alt="Description"
>
C. Mobile-Specific Optimizations
/* Ensure consistent heights on mobile */
@media (max-width: 768px) {
.hero-image {
min-height: 300px;
}
}
Testing & Monitoring
Test CLS
Tools:
- PageSpeed Insights - Lab and field data
- Web Vitals Extension - Real-time CLS
- Chrome DevTools - Experience panel
Test Your Zyro Site:
- Run PageSpeed Insights
- Check CLS in Core Web Vitals
- Review "Avoid large layout shifts" diagnostic
- Test on both mobile and desktop
Identify Layout Shifts
In Chrome DevTools:
- Open DevTools (F12)
- Go to Performance tab
- Enable "Web Vitals" in settings
- Record page load
- Look for red "Layout Shift" markers
- Click to see which elements shifted
In PageSpeed Insights:
- Scroll to "Diagnostics"
- Look for "Avoid large layout shifts"
- Shows elements that shifted
Monitor CLS Over Time
- Core Web Vitals report
- Shows CLS trends
- Identifies problem pages
Real User Monitoring:
- Use Web Vitals library
- Track CLS in analytics
- Monitor user impact
Zyro-Specific Quick Wins
Start here for immediate CLS improvements:
- Use Zyro's built-in image blocks (not custom HTML)
- Ensure all images have width and height attributes
- Use Zyro's built-in fonts (avoid custom fonts)
- Reserve space for third-party widgets (min-height)
- Load chat widgets below the fold or delayed
- Remove or optimize animations that affect layout
- Test on mobile devices
- Preload critical hero images
- Use aspect ratio boxes for video embeds
- Avoid injecting content above existing content
Common Zyro Layout Shift Sources
| Element | Common Issue | Fix |
|---|---|---|
| Hero Images | No dimensions | Use Zyro image blocks |
| Custom Fonts | FOUT/FOIT | Use built-in fonts or font-display: swap |
| Chat Widgets | Loads late | Delay or reserve space |
| Social Embeds | Dynamic height | Reserve space with min-height |
| Ads/Banners | Loads asynchronously | Reserve space |
| Forms | Dynamic validation | Reserve space for errors |
Debugging CLS
Step-by-Step Diagnosis
Run PageSpeed Insights
- Note CLS score
- Identify shifting elements
Use Chrome DevTools
- Record Performance
- Find Layout Shift markers
- Identify which elements shift
Test Different Pages
- Homepage often has most shifts
- Test key landing pages
- Mobile vs desktop
Isolate the Issue
- Temporarily remove third-party widgets
- Test without custom code
- Use default Zyro template
Fix and Retest
- Apply fixes one at a time
- Retest after each fix
- Document improvements
Advanced Techniques
CSS Containment
.container {
contain: layout; /* Isolate layout shifts */
}
Intersection Observer
Detect when elements enter viewport before loading:
const observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
loadWidget(entry.target);
}
});
});
document.querySelectorAll('.lazy-widget').forEach(function(el) {
observer.observe(el);
});
Next Steps
For general CLS optimization strategies, see CLS Optimization Guide.