Finding and Fixing Layout Shifts/CLS Issues

Over the past few months, I’ve been working on fixing Cumulative Layout Shift issues for my clients. CLS is a factor in the Core Web Vitals Google introduced in May 2020, used to measure a user’s experience related to the performance of a website. Layout shifts negatively affect a user’s experience, which is why Google is making it a factor in ranking starting mid-June.

Two websites I’ve worked on, with CLS fixes implemented in April. Improvements are as high as 65% with the results being more than 10% higher than the recommended. These numbers are from Google’s Chrome User Experience Report.

Largest Contentful Paint Cause and Remedy

The first core web vital, Largest Contentful Paint, is typically affected most by server & network speed. Optimizations can be made to improve it depending on what the largest element is on the page. If it’s an image, making sure that images are optimized well (webp file can decrease file sizes by quite a bit), and especially preloading the image (typically a banner or featured image) can drastically reduce LCP time. For content, simply having a good host and reducing render-blocking scripts is a good solution.

First Input Delay Cause and Remedy

The second core web vital, First Input Delay, is the time measured between when a user interacts with something on the page to when the browser starts executing any action associated it with it (whether an event handler or simply a link that opens in a new tab). While you may expect the delay to always be low due to the interaction being a high priority, scripts actively running in the background may cause the interaction response to be delayed. This is because there are only so many things a browser can do at once. If a heavy task is occurring in the background (for example, loading ads), the interaction may not be processed immediately. Reducing scripts is a good way to limit this, although unless you’re the developer behind the script causing issues there may not be much you can do beyond disabling it to fix the issue. Google Chrome’s Performance profiler is a good way to identify scripts that are taking up processing power on the main thread.

Cumulative Layout Shift Potential Causes

The third core web vital, Cumulative Layout Shift, can be the most difficult of the three to fix (although causes vary). The primary reason is that the tools required to find out 1) what’s shifting and 2) what’s causing the shift aren’t readily available. Any site scan service (including PageSpeed Insights, GTMetrix, and WebPageTest) are usually very poor tools to discover CLS issues. More than half the time, they won’t report CLS even though users are experiencing it. There’s a very good reason for this – most layout shifts don’t occur during or immediately after page load, which is the only window of time that any site scan will check. On top of that, many layout shift events don’t happen on the first view of the page, and may only happen near the bottom of the page or while scrolling. I’ve gone into more depth about how this happens with ads in this post, although poorly implemented lazy loading can also be a cause.

Profiling and Auditing for CLS Issues

Since automated tools like site scans aren’t a good candidate for replicating the average visitor’s experience, you’ll need to get your hands dirty with something more in-depth. Chrome’s Performance Profiling tool is the best way to find if layout shifts are happening, when they’re happening, and why they’re happening. Another advantage of using Chrome’s developer tools is you get access to other useful metrics like the network waterfall and especially the ability to block specific scripts or resources (which I’ll get into more later).

My process for checking for layout shifts usually beings with opening a new incognito window in Chrome, disabling caching in the Network tab, and in the Performance tab setting the network throttling to “Fast 3G” and CPU throttling to “4x” (side note: this is roughly the same amount of throttling that Lighthouse and most scans use to replicate a mobile user). I’ve been surprised how often layout shifts only happen when the network speed is low enough, or how much the performance of the device is a factor. I also set the screen size and user agent to emulate a mobile device.

Next, I start the profiler, then load one of the website’s post pages. It’s important to do all testing on a post page, and not the homepage. Collectively, your posts will make up a much larger percentage of visits than your homepage, and as far as SEO goes, it’s mostly per-URL and not site-wide. I wait until the page has completed loading, and stop the profiler. Chrome will list CWV events (including FID, which can be very useful since automated scans don’t record this at all), and by clicking on them, it will also show you (in the case of a LS) which element shifted, what it’s previous size and position was, and what it’s current size and position is. This is a good way to check for any obvious shifts that happen as the page load. Causes I’ve seen for layout shifts during this time vary, but they’ve usually been one of the following:

  • Images that don’t have a static width/height, meaning they “pop” in after the page loads and shift content.
  • CSS that should not have been deferred, typically caused by non-theme CSS from plugins. Social share widgets and WPRM’s recipe snippet box are the two most common sources I’ve seen. The solution is to either inline the CSS (Autoptimize has a feature for this) so it becomes render-blocking, or simply disable them.
  • Flash of unstyled text (FOUT), meaning when something larger like a header renders in the first view, the font it uses will switch when it’s CSS-configured font downloads. If the two fonts are different enough in size, it can shift content. Usually it’s not by much, however H1 headers with a large font size tend to inflate the issue. This is something I’ve found workarounds for, including a plugin fix I’m currently working on.

Finding Layout Shifts That Occur After Page Load

Sometimes I’ll get lucky and the issue will be one of the three. However, more often than not I’ll get a CLS of < 0.1. The next step in the process is to reload the page, and as soon as it finishes loading, start the profiler. I slowly scroll a bit down the page. Usually this triggers any ads that might load on the page. In order to make it easier to visually see any layout shifts, I usually stop and let the ads finish loading in. Once the network requests have stabilized, I continue scrolling slowly to the bottom of the page, and stop the profiler. This is usually where any layout shifts that are happening for visitors will show themselves. Typically any layout shifts that happen are a result of poorly implemented JS events. Dynamic ads (ads which show up between paragraphs) can be an obvious cause, but most ad providers have already implemented fixes (Mediavine, Adthrive, Blogher). I’ve noticed, however, that these CLS fixes aren’t always enabled by default, so it’s worth checking the linked posts to ensure you have it enabled. Also, a side note with Blogher; as of the writing of this post (June 11th) they only recently introduced a CLS fix for their dynamic ads, and they haven’t publicly put anything out about it – you may need to contact them to ensure the fix is enabled.

Since the layout shifts that scripts cause can be very difficult to diagnose, an easy way to find out which script is causing it is by disabling the script using the network request blocking feature in Chrome devtools. I usually start with disabling ads and re-running the profiler while scrolling through the page. This is also a great way to collect “proof” of issues to send to script developers, by profiling the page with and without the script enabled, and comparing results.