Eliminating Cumulative Layout Shift for Good
Cumulative Layout Shift measures visual stability. When elements move unexpectedly after initial render, users tap wrong buttons, lose reading position, and abandon the page. Google rates CLS good under 0.1 and poor above 0.25. Those numbers represent the fraction of the viewport affected multiplied by the distance the shifted element traveled. A full-width banner dropping down by 10% of the screen height generates a score of 0.1 by itself.
CLS failures are almost always deterministic and preventable. Unlike INP, which requires JavaScript profiling and often complex refactoring, CLS fixes are structural: reserve space before content loads, lock font metrics, and control when ads and embeds inject themselves into the layout. The engineering effort is low; the challenge is finding every shift on every page template.
This guide covers the full spectrum of CLS causes, from the obvious (images without dimensions) to the subtle (late-loading cookie banners, CSS animations that shift sibling elements, and web fonts causing text reflow). Each section includes the exact HTML or CSS change required, not just a description of the problem.
How CLS Is Calculated
Each layout shift is scored as the impact fraction (the combined area of all shifted elements relative to the viewport) multiplied by the distance fraction (how far the largest element moved as a fraction of the viewport height). These individual shift scores are summed over the page session. Shifts that occur within 500ms of a user interaction are excluded because they are considered expected responses to user actions.
The exclusion of interaction-triggered shifts is important. A dropdown menu expanding and pushing content down does not count toward CLS if it happens within 500ms of a click. But the same visual change happening during initial page load, or triggered by a lazy-loaded ad, does count. Understanding the timing window helps you distinguish which shifts you must fix and which are acceptable.
Images Without Explicit Dimensions
This is the most common CLS cause and the easiest to fix. When an img element has no width and height attributes, the browser allocates zero space for it until the image loads and reports its natural dimensions. Everything below the image shifts down as the image pushes in. The fix is two attributes: width and height on every img element, matching the intrinsic pixel dimensions of the image.
With CSS setting img { max-width: 100%; height: auto; } the explicit width and height attributes become an aspect ratio hint rather than a fixed size. The browser reserves space with the correct proportions before the image loads, preventing the shift. This works for both fixed-layout and responsive images. Apply the same principle to video elements and iframes: always provide width and height.
- Add explicit width and height attributes to every img element on the page
- Add width and height to video and iframe elements for the same reason
- Use the CSS aspect-ratio property as a fallback for dynamically sized containers
- Audit CMS-inserted images; many editors strip dimension attributes on upload
- Test with network throttling to simulate the space-reservation before image load
Web Fonts and Text Reflow
Web fonts cause CLS when a fallback system font renders first, then swaps to the web font which has different metrics (line height, letter spacing, word spacing). The text block changes size during the swap, shifting everything below it. The font-display descriptor controls when this swap happens.
font-display: swap causes the font to be used as soon as it loads, which means a visible swap and potential CLS. font-display: optional only uses the web font if it loads within a very short initial window; if it misses the window, the system font is used permanently for that page load. For body text, optional is the CLS-safe choice. For headings where brand consistency matters more, use size-adjust and ascent-override in the @font-face declaration to make the fallback font metrics match the web font, reducing the shift to near zero.
Ads, Embeds, and Dynamic Content
Ads are one of the most persistent CLS sources because ad networks inject content into reserved slots after the page loads, and the actual creative dimensions often differ from what was reserved. The solution is to reserve the correct minimum height for every ad slot with a min-height CSS rule before the ad loads, and to use the ad network's size mapping to predict the maximum ad height for each breakpoint.
For social media embeds (tweets, Instagram posts, YouTube videos), use the aspect-ratio CSS property or a padding-hack wrapper to reserve the correct space before the embed script loads. YouTube embeds with no reserved height are a common source of large CLS scores on content sites. A simple div with aspect-ratio: 16/9 wrapping the iframe eliminates the shift entirely.
- Reserve min-height for every ad slot before the ad creative loads
- Wrap YouTube and social embeds in an aspect-ratio container
- Use static placeholders (skeleton screens) for content loaded via API calls
- Avoid inserting banners above existing content after page load
- Test CLS with ads blocked and with ads enabled to find the ad-driven shift separately
Animations That Cause Layout Shift
Not all animations cause CLS, but some do. CSS transitions that change top, left, margin, padding, width, or height properties trigger layout recalculation and can shift sibling elements. Animations using transform: translate() and opacity do not affect layout and are both CLS-safe and GPU-accelerated for smooth rendering.
Replacing margin-based entrance animations with transform-based equivalents is a common CLS fix. Instead of animating margin-top from 20px to 0, animate transform: translateY(20px) to translateY(0). The visual effect is identical, but the layout is not affected and no sibling elements shift.
Cookie Banners and Late-Loading UI
Cookie consent banners that appear after initial render and push page content down are a frequent CLS source, particularly as privacy regulations require them across UAE and GCC markets. The fix is to position the banner as a fixed or sticky element that overlays content rather than displacing it. A fixed position banner does not cause CLS because it does not affect the layout flow of other elements.
Chat widgets, newsletter popups, and promotional bars that appear after a delay have the same problem. Reserve space for them or implement them as overlay elements. Any UI element that inserts into the document flow after initial render and after the 500ms interaction window is a CLS candidate.
Auditing and Monitoring CLS
The Chrome DevTools Performance panel shows layout shift events as pink bars on the Experience track. Clicking a layout shift shows the elements that moved and their shift score. This is the fastest way to find which elements are causing your CLS. For field data, the web-vitals library's onCLS function with the reportAllChanges option logs every individual shift with its target element.
After fixing CLS issues, verify with a real-device test on a slow connection before declaring the issue resolved. Some CLS shifts only appear on slow connections where fonts, images, and ads load in a different order than on fast connections.
CLS is the most preventable of the three Core Web Vitals. Every major cause has a structural fix: dimensions for images, aspect-ratio containers for embeds, font-display control for fonts, reserved slots for ads, and overlay positioning for late-loading UI. The audit process is straightforward: record a page load in Chrome DevTools and inspect the Experience track for pink shift events. For mobile-dominant markets like Dubai and the UAE, CLS fixes are especially important because small viewports amplify the visual impact of layout shifts and the tap accuracy problems they cause.
Frequently asked questions
Does CLS only count shifts during initial page load?
No. CLS accumulates throughout the entire page session. Shifts triggered by lazy-loaded images, infinite scroll loading new content, and late-injected ads all contribute. However, shifts that occur within 500ms of a direct user interaction (click, tap, keypress) are excluded as they are considered intentional responses to user actions.
Will adding width and height attributes break my responsive images?
No. When you set img { max-width: 100%; height: auto; } in your CSS, the width and height attributes become aspect ratio hints. The browser uses them to reserve space proportionally before the image loads, but the actual rendered size is still controlled by your CSS. The image remains fully responsive.
How do I fix CLS from a third-party ad network I do not control?
Reserve space using CSS min-height on the ad container before the ad loads. Set min-height to the largest creative size you expect for that slot at each breakpoint. If the ad loads a smaller creative, the extra empty space is less harmful than a large layout shift. Some publishers use min-height and then collapse the slot if no ad fills it using a small script.
Is font-display: optional always the right choice to prevent font CLS?
It depends on your branding requirements. font-display: optional prevents CLS entirely by only using the web font if it loads within a brief window, otherwise falling back to the system font permanently. If brand font consistency matters more than CLS on slow connections, use size-adjust and ascent-override to match the fallback font metrics to the web font instead.