Fix CLS Issues on Magnoliacms (Layout Shift) | OpsBlu Docs

Fix CLS Issues on Magnoliacms (Layout Shift)

Stabilize Magnolia CMS layouts by reserving component area containers, sizing DAM image renditions, and preloading theme fonts.

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. Magnolia CMS generates CLS from component areas rendering at variable heights, DAM image rendition loading, and personalization variant swaps.

Magnolia-Specific CLS Causes

  • Component area height variability -- Magnolia areas contain components that render at different heights depending on content
  • DAM rendition loading -- images from Magnolia's DAM load at different sizes depending on the rendition
  • Personalization module -- Magnolia's personalization swaps content variants client-side after initial render
  • Page editor overlay -- if editor scripts leak to production, the page editor overlay shifts content
  • FreeMarker conditional rendering -- templates with <#if> blocks render different amounts of content, changing page height

Fixes

1. Reserve Space for Component Areas

<#-- In your area template -->
<div class="content-area" style="min-height: 400px; contain: layout;">
  [@cms.area name="main" /]
</div>

<div class="sidebar-area" style="min-height: 300px; contain: layout;">
  [@cms.area name="sidebar" /]
</div>
/* Component-level containment */
.magnolia-component { contain: layout; min-height: 50px; }

/* Specific component types */
[data-component-type="hero"] { min-height: 500px; aspect-ratio: 16/6; }
[data-component-type="text-image"] { min-height: 250px; }
[data-component-type="carousel"] { min-height: 400px; }

2. Set DAM Image Dimensions

<#-- Always include dimensions from DAM metadata -->
<#assign asset = damfn.getAsset(content.image)>
<#if asset?has_content>
  <#assign rendition = damfn.getRendition(asset, "thumbnail")>
  <img
    src="${rendition.getLink()}"
    width="${rendition.getWidth()}"
    height="${rendition.getHeight()}"
    alt="${asset.getCaption()!''}"
    loading="lazy"
    style="aspect-ratio: ${rendition.getWidth()} / ${rendition.getHeight()};"
  >
</#if>

3. Handle Personalization CLS

/* Reserve space for personalization slots */
.personalization-slot {
  min-height: 200px;
  contain: layout;
  transition: opacity 0.2s;
}

.personalization-slot.loading {
  opacity: 0.8;
}

4. Prevent Editor Overlay in Production

<#-- Ensure editor scripts only load in author instance -->
<#if !cmsfn.isEditMode()>
  <#-- Production-only code -->
</#if>

5. Preload Theme Fonts

<link rel="preload" href="${ctx.contextPath}/themes/mytheme/fonts/brand.woff2"
      as="font" type="font/woff2" crossorigin />
@font-face {
  font-family: 'BrandFont';
  src: url('fonts/brand.woff2') format('woff2');
  font-display: swap;
}

Measuring CLS on Magnolia

  1. Chrome DevTools Performance tab -- look for layout-shift entries during component area rendering
  2. Test pages with many components -- more components in an area = higher CLS risk
  3. Test personalized pages -- personalization variant swaps cause CLS
  4. Test author vs. public instance -- author instance includes editor overlays that affect CLS

Analytics Script Impact

  • Magnolia's built-in analytics is server-side -- minimal CLS
  • Third-party analytics added via FreeMarker templates should use async/defer
  • Personalization A/B testing scripts that swap DOM elements are the biggest CLS risk