General Guide: See Global CLS Guide for universal concepts and fixes.
What is CLS?
Cumulative Layout Shift measures visual stability. Google recommends CLS under 0.1. Fork CMS generates CLS from unsized media library images, dynamically-rendered module widgets (blog, FAQ, search), and theme font loading.
Fork CMS-Specific CLS Causes
- Media library images without dimensions -- Fork CMS outputs images from the media manager without explicit
width/heightattributes - Module widget positions -- modules placed in widget positions (sidebar, footer) load their content dynamically and shift surrounding elements
- Blog module listings -- variable-length post excerpts and optional featured images create inconsistent card heights
- FAQ accordion rendering -- FAQ module items animate open/closed, shifting content below
- Theme font loading -- Fork CMS themes load web fonts via CSS files without
font-display: swap
Fixes
1. Add Image Dimensions in Templates
Override Fork's image rendering in your theme:
{# In your theme's Twig templates #}
{% if post.image %}
<div class="post-image" style="aspect-ratio: 16/9; overflow: hidden; background: #f0f0f0;">
<img
src="{{ FRONTEND_FILES_URL }}/{{ post.image }}"
width="800" height="450"
alt="{{ post.title }}"
loading="lazy"
style="width: 100%; height: 100%; object-fit: cover;"
>
</div>
{% else %}
<div class="post-image-placeholder" style="aspect-ratio: 16/9; background: #f0f0f0;"></div>
{% endif %}
2. Reserve Space for Widget Positions
Fork CMS uses named positions for module widgets. Set minimum heights:
/* Widget position containment */
.position-sidebar { min-height: 300px; contain: layout; }
.position-footer { min-height: 200px; contain: layout; }
/* Individual widget modules */
.widget-blog-recent { min-height: 250px; contain: layout; }
.widget-blog-categories { min-height: 150px; contain: layout; }
.widget-search { min-height: 60px; contain: layout; }
.widget-faq { min-height: 200px; contain: layout; }
3. Stabilize Blog Listings
/* Consistent blog post card heights */
.blog-list .post-item {
min-height: 200px;
contain: layout;
}
/* Fixed-height excerpts prevent variable card sizes */
.post-excerpt {
max-height: 4.5em;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
4. Fix FAQ Accordion CLS
/* Prevent FAQ items from shifting content below */
.faq-container {
contain: layout;
}
/* Use max-height transition instead of height:auto */
.faq-answer {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
}
.faq-answer.open {
max-height: 500px; /* Large enough for any answer */
}
5. Preload Theme Fonts
{# In base layout <head> #}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preload" href="{{ THEME_URL }}/fonts/custom.woff2" as="font" type="font/woff2" crossorigin>
@font-face {
font-family: 'CustomFont';
src: url('fonts/custom.woff2') format('woff2');
font-display: swap;
size-adjust: 103%;
}
Measuring CLS on Fork CMS
- Chrome DevTools Performance tab -- record and filter for layout shifts
- Test widget-heavy pages -- pages with sidebar widgets and footer modules have the most CLS risk
- Test blog listings vs. single posts -- different CLS profiles
- Mobile testing -- Fork CMS responsive layouts often reflow differently on mobile
Analytics Script Impact
- Fork CMS's analytics module is lightweight and server-side -- minimal CLS impact
- Cookie consent implementations should use
position: fixedoverlays - If adding third-party analytics via custom code, use
async/defer