Fixing Cumulative Layout Shift (CLS): Why Your Page Jumps and How to Stop It
Stop content jumping around — fix layout shifts for good.
Cumulative Layout Shift (CLS) is the Core Web Vital that measures visual stability — specifically, how much the page content unexpectedly moves around as it loads. You've experienced poor CLS when you're about to tap a button and an image loads above it, pushing the button down the page so you tap something completely different instead. Or when you're reading an article and the text suddenly jumps down because an advertisement loaded above it. These shifts are frustrating, occasionally damaging (accidentally tapping an ad or a delete button), and a measurable negative signal for Google.
A CLS score under 0.1 is considered good; above 0.25 is poor. Unlike LCP and INP, which are primarily about speed, CLS is about predictability — making sure content stays where it appeared when the page first rendered. At Xpose, CLS is often the Core Web Vital we see most neglected on client sites, largely because it's the least intuitive to understand. This guide explains the main causes and the specific code changes that resolve them.
The Main Causes of Layout Shift
Layout shifts are almost always caused by content appearing on the page after initial render that doesn't have reserved space. The most common culprits are: images and videos without explicit width and height attributes (the browser doesn't know how much space to reserve before the resource loads, so it collapses the space and then expands it); web fonts that cause text to reflow when they load (the font changes character widths, causing text to reflow and push surrounding content); advertisements, embeds, and third-party widgets that inject content of unknown dimensions; and dynamically injected content like cookie banners, notification bars, and chat widgets that appear above existing content after page load.
Diagnose your specific layout shifts using the Chrome DevTools Layout Shift Regions feature (enable it in DevTools > Rendering panel > Layout Shift Regions) or by running PageSpeed Insights, which lists the specific elements causing CLS in the Diagnostics section. The CLS score is cumulative — multiple small shifts add up — so it's common to find several contributing elements, each responsible for a fraction of the total score.
Fixing Image, Video, and Font Layout Shifts
The fix for images and videos without explicit dimensions is straightforward: add width and height attributes to every image element in your HTML. When these attributes are present, the browser can calculate the aspect ratio before the image loads and reserve the correct amount of vertical space. You don't need to use the exact pixel dimensions as the displayed size — CSS controls the final rendered size — but the aspect ratio defined by the width and height attributes tells the browser how to proportion the placeholder space. For images in a CMS like WordPress, ensure your theme's image templates include these attributes; many older WordPress themes do not.
For web fonts, the most effective CLS fix is to add font-display: swap to your @font-face declarations. This tells the browser to show a system font immediately and swap to the custom font when it loads, rather than hiding text until the font is available. The swap can still cause a small shift, but it's typically much smaller than the shift caused by content reflow when late-loading fonts change character widths. Preloading your most critical fonts using <link rel="preload"> in the <head> reduces the swap delay further. At Xpose, we combine font-display: swap with font preloading for all custom typefaces, and consistently achieve CLS scores under 0.05 for sites with custom fonts.
Ads, Third-Party Embeds, and Dynamic Content
Advertisements and third-party embeds (social media feeds, YouTube videos, booking widgets) cause CLS when they load into a container that didn't reserve adequate space for them. Fix this by wrapping embeds in a container with explicit dimensions that match the expected ad or embed size, or by using the CSS aspect-ratio property to reserve proportional space. For ads that vary in size, use the largest expected ad size as your minimum reserved space and accept that smaller ads will leave some whitespace — this is preferable to content jumping.
Dynamic content injected by JavaScript — cookie consent banners, chat widgets, subscription nag bars — should be designed to appear below the fold or in a fixed position (such as a sticky bottom bar) rather than inserting above existing content. A cookie banner that pushes the entire page content down by 80 pixels creates a substantial layout shift. Fixed-position overlays avoid this by placing themselves in the browser chrome rather than in the document flow. At Xpose, when we implement cookie consent solutions for clients, we always use fixed-position banners for exactly this reason. If you're using a chat widget that appears in the corner of the screen, check that it's using position: fixed and not position: absolute within the document — the former causes no layout shift, the latter typically does.
Common questions.
How do I measure my CLS score?
Does a good CLS score improve my Google rankings?
My page looks stable to me — why does Google report high CLS?
More on web design & ux.
Want a hand putting this into practice?
Book a free, no-obligation consultation with a Norwich-based specialist.
Let's put your business in a better light.
Book a free, no-pressure consultation. We'll talk through your goals and tell you honestly what we'd do — whether you work with us or not.