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. Bludit's flat-file architecture means CLS issues come from theme templates, plugin-injected elements, and missing image dimensions rather than server-side dynamic content.
Bludit-Specific CLS Causes
- Cover images without dimensions -- Bludit's
$page->coverImage()outputs<img>tags withoutwidth/heightin most default themes - Plugin output injection -- plugins like cookie consent, social sharing, and notification bars inject elements into the DOM after initial render
- Theme font loading -- custom themes loading Google Fonts via
@importcause FOUT and text reflow - Sidebar widget reflow -- Bludit plugins that render sidebar content (tag clouds, recent posts) load asynchronously
- Ad injection -- manually placed ad code in theme templates without reserved space
Fixes
1. Add Image Dimensions in Theme Templates
Most Bludit themes output cover images without size attributes. Fix in your theme's page template:
<!-- themes/yourtheme/php/page.php -->
<?php if ($page->coverImage(true)): ?>
<?php
$imgPath = PATH_UPLOADS . basename($page->coverImage(true));
$imgSize = file_exists($imgPath) ? getimagesize($imgPath) : [1200, 630];
?>
<div class="cover-image" style="aspect-ratio: <?php echo $imgSize[0]; ?>/<?php echo $imgSize[1]; ?>;">
<img
src="<?php echo $page->coverImage(true); ?>"
width="<?php echo $imgSize[0]; ?>"
height="<?php echo $imgSize[1]; ?>"
alt="<?php echo $page->title(); ?>"
style="width: 100%; height: auto;"
>
</div>
<?php endif; ?>
For blog listing pages where multiple post thumbnails load:
<!-- themes/yourtheme/php/blog.php -->
<?php foreach ($content as $page): ?>
<article class="post-card">
<?php if ($page->coverImage(true)): ?>
<div class="post-thumbnail" style="aspect-ratio: 16/9; overflow: hidden;">
<img
src="<?php echo $page->coverImage(true); ?>"
width="400" height="225"
alt="<?php echo $page->title(); ?>"
loading="lazy"
style="width: 100%; height: 100%; object-fit: cover;"
>
</div>
<?php endif; ?>
<h2><?php echo $page->title(); ?></h2>
</article>
<?php endforeach; ?>
2. Constrain Plugin Output Areas
Reserve space for plugin-injected content in your theme's CSS:
/* Reserve space for cookie consent plugin */
.plugin-cookie-consent {
position: fixed; /* Use fixed instead of relative to avoid pushing content */
bottom: 0;
left: 0;
right: 0;
z-index: 9999;
}
/* Reserve sidebar plugin areas */
.sidebar .plugin-widget {
min-height: 100px;
contain: layout;
}
/* Social sharing bar -- prevent injection shift */
.social-share-container {
min-height: 40px;
contain: layout;
}
3. Fix Font Loading in Themes
Bludit themes commonly load fonts with @import which blocks rendering:
<!-- BAD: In themes/yourtheme/css/style.css -->
<!-- @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700'); -->
<!-- GOOD: In themes/yourtheme/php/head.php -->
<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=Open+Sans:wght@400;700&display=swap" rel="stylesheet" />
/* Add fallback metrics to minimize text reflow */
body {
font-family: 'Open Sans', 'Open Sans Fallback', Arial, sans-serif;
}
@font-face {
font-family: 'Open Sans Fallback';
src: local('Arial');
size-adjust: 105%;
ascent-override: 110%;
descent-override: 30%;
}
4. Prevent Inline Content Injection
If your theme dynamically injects notifications or banners via JavaScript:
// BAD: Inserting at top of body pushes everything down
document.body.insertBefore(banner, document.body.firstChild);
// GOOD: Use a pre-reserved slot in your theme template
<div id="notification-slot" style="min-height: 0; transition: min-height 0.3s;">
</div>
<script>
// Smoothly expand the slot instead of pushing content
var slot = document.getElementById('notification-slot');
slot.innerHTML = '<div class="notification">Your message here</div>';
slot.style.minHeight = '50px';
</script>
Measuring CLS on Bludit
- Chrome DevTools Performance tab -- record a page load, then filter the "Experience" lane for layout shifts. Click each shift to see which DOM node moved.
- PageSpeed Insights -- run on both homepage (blog listing) and individual post pages
- Test with plugins disabled -- Bludit's Settings > Plugins lets you disable plugins individually; test CLS after each disable to find the culprit
- Mobile testing -- Bludit themes are often desktop-first, with mobile layouts that have more CLS from reflowing images and sidebars
Analytics Script Impact
- Bludit's Simple Stats plugin -- server-side only, no CLS impact
- Manually added analytics -- if placed in
head.php, ensure they do not inject visible elements (tracking pixels are fine, but chat widgets or survey popups cause CLS) - Ad code -- any manually placed AdSense or ad network code needs explicit
min-heightcontainers; Bludit has no ad management plugin to handle this automatically