Skip to main content
CLS Prevention Strategies

Snapglo Reveals 5 CLS Prevention Mistakes You Must Fix Now

Cumulative Layout Shift (CLS) is one of the most frustrating metrics to stabilize. You set dimensions on images, preload fonts, reserve ad space—yet the score still jumps. We've seen teams pour weeks into CLS optimization only to watch their progress slip after the next deploy. The problem isn't effort; it's that certain well-intentioned fixes actually make things worse, or they address symptoms while ignoring the root cause. In this guide from Snapglo, we reveal five CLS prevention mistakes that we see repeated across projects, and we show you exactly how to fix each one. If you're tired of chasing layout shifts that keep reappearing, read on. Where CLS Shows Up in Real Projects Layout shift doesn't happen in a vacuum. It appears when the browser has already painted a frame, and then new content loads that pushes existing elements down or sideways.

Cumulative Layout Shift (CLS) is one of the most frustrating metrics to stabilize. You set dimensions on images, preload fonts, reserve ad space—yet the score still jumps. We've seen teams pour weeks into CLS optimization only to watch their progress slip after the next deploy. The problem isn't effort; it's that certain well-intentioned fixes actually make things worse, or they address symptoms while ignoring the root cause. In this guide from Snapglo, we reveal five CLS prevention mistakes that we see repeated across projects, and we show you exactly how to fix each one. If you're tired of chasing layout shifts that keep reappearing, read on.

Where CLS Shows Up in Real Projects

Layout shift doesn't happen in a vacuum. It appears when the browser has already painted a frame, and then new content loads that pushes existing elements down or sideways. The most common triggers are images without explicit dimensions, late-loading ads, embedded media, web fonts that swap after rendering, and dynamic content injected by third-party scripts. In our work with various teams, we've seen CLS spikes appear in the same places: product listing pages where infinite scroll inserts items above the fold, article pages with sticky headers that resize, and checkout flows where error messages pop in without reserved space.

One scenario we often encounter is a news site that loads a hero image lazily. The developer sets loading='lazy' on the <img> tag and assumes that's enough. But without explicit width and height attributes, the browser reserves zero space until the image begins loading. When it finally loads, it shoves the headline and intro text downward, causing a large shift. The fix is straightforward—always include dimensions—but many teams forget that lazy loading does not imply layout stability.

Another typical hotspot is the footer. Third-party widgets for social feeds, customer reviews, or newsletter signups often load after the main content. If they don't have a reserved container with a fixed height, they can push the footer down and cause a shift that affects the entire page. We've seen CLS scores improve by 0.1 or more just by giving each widget a min-height placeholder.

Ads are a notorious source of CLS. Ad networks often serve creatives of varying sizes, and if the container isn't sized to accommodate the largest expected ad, the page jumps when the ad loads. Some teams try to mitigate this by setting a fixed height on the ad container, but that can backfire if the ad is smaller—leaving a blank gray box. The better approach is to use a placeholder that matches the most common ad size and accept that occasional empty space is less harmful than a layout shift.

Fonts also contribute to CLS more than many developers realize. When a web font loads after the fallback font has already been painted, the text reflows because the two fonts have different metrics. This shift is often small in isolation, but across a page with many text blocks, it adds up. The fix is to use font-display: swap with a short fallback period, or preload the font so it arrives before the first paint. We'll dive deeper into font strategies later.

Finally, single-page applications (SPAs) have their own CLS challenges. Route transitions that fetch data asynchronously can cause content to pop in after the new view has already rendered. Frameworks like React or Vue often re-render components in stages, and if a component that affects layout loads late, the page shifts. This requires careful orchestration of loading states and skeleton screens that match the final layout dimensions.

Foundations That Teams Often Misunderstand

Before we get into specific mistakes, it's worth clarifying what CLS actually measures. CLS is the sum of all unexpected layout shifts that occur during the entire lifespan of a page, weighted by the impact of each shift. A shift is considered unexpected if it's not triggered by a user interaction. The score ranges from 0 to 1, where 0.1 or less is considered good, 0.25 or less needs improvement, and above 0.25 is poor. The metric is designed to capture how much the content jumps around, which directly affects user experience—especially for people reading or trying to tap a button.

One common misunderstanding is that setting width and height on images is optional if you use aspect-ratio in CSS. While aspect-ratio does help the browser calculate dimensions, it only works if the image container has a defined width. If the container itself is fluid, the aspect ratio alone may not prevent shifts because the height is still computed from the width, which can change. The safest approach is to always include explicit dimensions in the HTML, and then use CSS to handle responsive scaling.

Another misconception is that CLS only matters above the fold. While shifts above the fold are more impactful because they affect the initial view, shifts anywhere on the page contribute to the score. A large shift in the footer can still hurt the overall CLS, especially if the user scrolls down and encounters it. We've seen pages with a good above-the-fold CLS but a terrible overall score because of late-loading content in the middle or bottom of the page.

Teams also confuse CLS with other performance metrics. For example, Largest Contentful Paint (LCP) measures loading speed, while CLS measures stability. A page can load fast but still have terrible CLS if elements move after paint. Optimizing for LCP alone—like preloading the hero image—can actually hurt CLS if that image's dimensions aren't reserved. The two metrics need to be balanced.

Finally, many people think that if they use a CSS animation or transition, it won't count as a layout shift. That's true only if the animation triggers a CSS property that doesn't affect layout, like transform or opacity. Animating width, height, margin, or top can still cause shifts and will be counted by the CLS metric. Stick to transform-based animations for moving elements.

Patterns That Usually Work

Over time, the web performance community has converged on a set of reliable CLS prevention techniques. These aren't silver bullets, but they form a solid foundation that most projects can adopt.

Always Set Explicit Dimensions on Media

Every <img>, <video>, <iframe>, and <embed> should have width and height attributes in the HTML. This lets the browser calculate the aspect ratio and reserve the correct amount of space before the media loads. For responsive images, you can combine this with CSS max-width: 100% and height: auto—the browser will use the attributes to compute the aspect ratio and scale accordingly. This pattern alone eliminates the majority of image-related CLS.

Reserve Space for Dynamic Content

Any element that loads after the initial render—ads, embeds, widgets, notifications—needs a placeholder container with a minimum height. The height should be based on the largest expected variant. For ads, use the most common ad size (e.g., 300x250) and set min-height on the container. For embeds like YouTube videos, use the aspect ratio technique: wrap the embed in a container with padding-bottom: 56.25% (for 16:9) and position the iframe absolutely inside. This ensures the space is reserved even if the embed loads late.

Preload Fonts and Use font-display: swap

Fonts are a major source of invisible CLS. The font-display: swap CSS descriptor tells the browser to render text immediately with a fallback font, then swap to the web font when it loads. However, if the fallback and web fonts have different metrics, the swap causes a shift. To minimize this, preload your primary fonts using <link rel='preload' as='font'> so they arrive before the first paint. You can also adjust the font-display value to optional if you're okay with the fallback font remaining in some cases, but that can affect brand consistency. A better approach is to use a font subset or a variable font that loads quickly.

Use Skeleton Screens with Correct Dimensions

For SPAs or pages with async content, skeleton screens (gray placeholder shapes) can prevent layout shifts if they match the final content's dimensions. The key is to measure the actual content size and set the skeleton's width and height accordingly. If the skeleton is too small, content will push it down; if too large, it will shrink and cause a shift in the opposite direction. Use CSS aspect-ratio or explicit dimensions on skeleton elements to keep them stable.

Test with Real User Monitoring (RUM)

Lab tools like Lighthouse give you a controlled CLS score, but real users may experience different shifts due to varying network conditions, devices, and third-party scripts. Use a RUM service (like the Chrome User Experience Report or a dedicated analytics tool) to see the distribution of CLS across your actual audience. This helps you prioritize fixes that affect the most users, not just the lab environment.

Anti-Patterns That Teams Keep Reverting To

Despite the known best practices, we see teams fall back into the same counterproductive habits. Here are the most common anti-patterns and why they fail.

Relying on Lazy Loading to Fix Layout

Lazy loading defers the loading of off-screen images until they are near the viewport. It saves bandwidth but does nothing for layout stability. In fact, lazy-loaded images that lack explicit dimensions are a major CLS culprit because the browser doesn't know their size until they load. The fix is to always include dimensions, even on lazy-loaded images. Some developers think that loading='lazy' combined with aspect-ratio in CSS is enough, but as mentioned earlier, if the container width is fluid, the height calculation can still be off.

Setting Fixed Heights on Ad Containers

To prevent ad-induced shifts, some teams set a fixed height on the ad container. This works if the ad always matches that height, but ads often come in multiple sizes. If a smaller ad loads, the container remains at the fixed height, leaving empty space. That empty space isn't a layout shift, but it looks bad and can reduce ad revenue. Worse, if the ad is larger than the fixed height, it will overflow and cause a shift. A better approach is to use min-height with a value that covers the most common ad size, and accept that occasionally the container will be slightly larger than the ad.

Using CSS Animations on Layout Properties

Animating width, height, margin, or padding can cause layout shifts even if the animation is smooth. The browser repaints the element at each frame, and if the element's size changes, it pushes other content around. This is counted as a layout shift. To animate size changes, use transform: scale() instead, which doesn't affect layout. Similarly, for sliding elements, use transform: translateX() rather than animating left or margin-left.

Ignoring Third-Party Scripts

Many teams focus on their own code but neglect third-party scripts like analytics, chatbots, or social media widgets. These scripts often inject elements dynamically without reserving space. A common example is a cookie consent banner that appears after the page has loaded, pushing the header down. The fix is to reserve space for the banner in the HTML, or load it synchronously before the first paint. If that's not possible, at least give it a fixed height container.

Over-Optimizing for One Viewport

Some developers test CLS only on desktop or only on a specific phone model. But CLS can vary dramatically across viewports. An image that fits perfectly on a 375px screen might cause a shift on a 414px screen if the aspect ratio isn't preserved. Always test on multiple viewport sizes, including tablets and large desktops. Use responsive design techniques that maintain aspect ratios across breakpoints.

Maintenance, Drift, and Long-Term Costs

Fixing CLS is not a one-time task. Over time, teams add new features, swap libraries, or update third-party integrations, and each change can reintroduce layout shifts. We've seen sites that passed Core Web Vitals in one quarter only to fail the next because a developer added a new hero banner without dimensions.

How Drift Happens

Drift occurs when the original CLS fixes are not documented or enforced. For example, a team might set up a build-time check that ensures all images have width and height attributes. But if a new developer joins and uses a different component that doesn't enforce this rule, images without dimensions can slip through. Similarly, a content editor might upload an image via a CMS that strips the dimensions, and the site's front-end doesn't add them automatically.

Cost of Monitoring

Continuous CLS monitoring requires tooling. You need a RUM solution that tracks CLS over time and alerts you when the score degrades. This costs money and engineering time to set up and maintain. Some teams rely solely on Lighthouse CI, which runs in a controlled environment and may not catch real-user shifts. The cost of not monitoring, however, is higher: a bad CLS score can hurt SEO rankings and user retention.

Third-Party Changes

Third-party services update their code without warning. An ad network might start serving a new creative size that doesn't fit your placeholder. A social widget might change its loading behavior. To mitigate this, you can wrap third-party content in a container with a min-height that covers the largest known size, and periodically test with a staging environment that simulates the latest versions of these scripts.

Team Communication

CLS prevention is a cross-team responsibility. Designers need to provide assets with known dimensions. Developers need to implement placeholders. QA needs to test for layout shifts. If any of these groups drop the ball, CLS can regress. Regular performance reviews and shared dashboards help keep everyone aligned.

When Not to Use This Approach

Not every CLS prevention technique is appropriate for every situation. Here are cases where the standard advice may not apply.

When You Can't Control the Content

If your site relies heavily on user-generated content (UGC) like forums, comments, or image uploads, you can't guarantee that every image will have dimensions. In that case, you can use a client-side script that reads the image's natural dimensions after load and sets them programmatically, but that introduces a delay and may cause a small shift. Alternatively, you can wrap UGC in a container that collapses until the content is ready, using a loading spinner to occupy space. This isn't perfect, but it's better than letting images shift without any placeholder.

When Ads Are the Primary Revenue Source

Ad networks often require flexibility in creative sizes to maximize fill rates. If you set a rigid placeholder, you might lose revenue because the ad server can't serve a larger, higher-paying ad. In this case, you have to balance CLS against revenue. One compromise is to use a placeholder that matches the most common ad size and accept that occasional shifts from larger ads are a trade-off. Some sites use a 'sticky' ad container that overlays content instead of pushing it, but that can interfere with user experience in other ways.

When Using a CMS That Strips Attributes

Some CMS platforms automatically remove width and height from images to force responsive behavior. If you can't modify the CMS, you can add a server-side filter that reinserts dimensions based on the image's actual dimensions, or use a client-side script that calculates aspect ratio from the image's source. This adds complexity but can salvage CLS.

When Fonts Are Critical for Brand

If your brand relies on a specific custom font that is large and slow to load, using font-display: swap might cause a visible flash of unstyled text (FOUT) that some stakeholders find unacceptable. In that case, you might choose font-display: block which gives the font a short block period before falling back, but this can delay text rendering and affect LCP. There's no perfect solution; you need to test which trade-off your users tolerate better.

When You Have a Single-Page App with Complex State

In SPAs, layout shifts often happen during route transitions when components mount in stages. The standard fix is to use skeleton screens, but if the skeleton doesn't match the final layout exactly, it can cause a shift when the real content replaces it. In some cases, it's better to delay rendering until all data is available, even if that means a longer blank screen. This is a trade-off between perceived performance (loading time) and stability. Measure both to decide.

Open Questions and Common Fixes

We often get asked the same questions about CLS prevention. Here are answers to the most frequent ones.

Does setting width and height on images cause distortion on mobile?

No, if you combine them with CSS max-width: 100% and height: auto. The browser uses the HTML attributes to calculate the aspect ratio, then scales the image down to fit the container while preserving that ratio. The image will not distort.

What about background images? Do they cause CLS?

Background images set via CSS do not cause layout shifts because they don't affect the document flow. However, if the background image is used on a container that has no intrinsic size, the container might collapse and then expand when the image loads, causing a shift. To prevent that, give the container explicit dimensions or a padding-bottom trick based on the aspect ratio.

How do I handle CLS from web fonts without hurting LCP?

Preload the font using <link rel='preload'> and set font-display: swap with a short fallback period (like 100ms). This ensures the font arrives before the first paint if possible, and if not, the fallback is shown briefly. You can also use a font subset that includes only the characters you need, reducing file size.

Can I use JavaScript to dynamically set dimensions after load?

Yes, but it's a fallback, not a first-line solution. If you must use JS, run it as early as possible (in the <head> or as a blocking script) to set dimensions before the browser paints. However, this adds a dependency on JavaScript and can delay rendering. It's better to set dimensions in HTML or server-side.

How do I test CLS for real users?

Use the Chrome User Experience Report (CrUX) in PageSpeed Insights, or set up your own RUM with the web-vitals library. This gives you a distribution of CLS scores across your user base, so you can see the 75th percentile (the metric used for Core Web Vitals).

What's the biggest mistake teams make with CLS?

Thinking that lazy loading or responsive images alone will fix it. The root cause is almost always missing dimensions or unreserved space. Focus on those two things first.

Summary and Next Experiments

CLS prevention is not about a single magic fix—it's about a systematic approach to reserving space for every element that loads after the initial paint. The five mistakes we covered—skipping dimensions, ignoring font swap, using lazy loading as a crutch, setting fixed heights on ads, and neglecting third-party scripts—are the most common reasons teams fail to stabilize their layout.

To move forward, we recommend the following next steps:

  1. Audit your current CLS score using both lab (Lighthouse) and field (CrUX) data. Identify the pages with the worst scores and prioritize them.
  2. Add a build-time check that warns if any <img> or <iframe> is missing width and height attributes. Many static site generators and frameworks have plugins for this.
  3. Reserve space for all third-party widgets by wrapping them in containers with a min-height set to the largest expected size. Test with real third-party scripts in staging.
  4. Preload your primary fonts and use font-display: swap with a short fallback period. Measure the impact on both CLS and LCP.
  5. Set up a RUM dashboard that tracks CLS over time and alerts you if the 75th percentile exceeds 0.1. Review it weekly as part of your performance monitoring.

CLS is a metric that rewards discipline. Every time you add a new element to a page, ask yourself: 'Have I reserved its space?' If the answer is yes, you're on the right track. If not, you're likely introducing a shift that will frustrate users and hurt your search rankings. Start with the fixes above, and you'll see your CLS score drop—and stay down.

Share this article:

Comments (0)

No comments yet. Be the first to comment!