Website performance audits and tools

Cumulative Layout Shift

Measuring (and removing) annoying browser jumps.

This is part 1 of An introduction to Core Web Vitals, a 3 part series about Core Web Vitals. Core Web Vitals refer to three key metrics that provide a good measure of your website’s user experience. However, in June 2021, Core Web Vitals became one of the ranking signals that Google uses to rank its search engine results. Thus Core Web Vitals began to not only impact conversions but traffic as well. As such, they are one of the most important parts of SiteImp audits.

This article

This article, I’m going to start this three part tutorial by talking about Cumulative Layout Shift (CLS). I chose to start with Cumulative Layout Shift because I just finished some optimizations to fix this site’s CLS scores so it’s top of mind. It’s also my favourite of the Core Web Vitals.

Cumulative Layout Shift refers to the unexpected shifting of website elements while the page is downloaded. These are unexpected changes, so they are not the result of any user input. Instead, CLS refers to the weird jerkiness (??) that we have all experienced.

Have you ever loaded up an advertising news site, started scrolling down as you read and then had the whole page jump back up to the very top when the page is finished downloading? If so, you’ve experienced (and likely been annoyed by) layout shift. Or have you ever loaded up a contact form, started typing your message and had the page jump right back up to the very top? If so, again, that’s another example of a layout shift.

Cumulative layout shift is the total of all of those unexpected layout shifts.

What causes layout shifting

According to Google, five main things cause layout shifts:

  1. Images without dimensions.
  2. Ads, embeds, iframes (and related elements) that don’t have dimensions.
  3. Dynamically injected content.
  4. Web fonts that cause “Flash of Invisible Text” (FOIT) and “Flash of Unstyled Text” (FOUT).
  5. Tying DOM updates to network responses.

I’ll take a moment to talk about these issues.

<img src="picture.jpg">

Do you notice what’s missing? Height and width attributes. <img> elements need height and width attributes or they will cause layout shifts. Instead of closing off your img elements like that, try this:

<img src="picture.jpg" height="300" width="300" alt="Either a cat picture or a symptom of toxoplasmosis. Who knows?">

I added three things in there. Height, width and alt elements. Height and width will prevent layout shift and alt elements make your website more accessible for people who use screen readers. SiteImp currently doesn’t provide much support for accessibility testing, but that’s on my roadmap for next week.

I’ll use this case to illustrate the root cause behind layout shift. When a browser encounters an image attribute, it has to download that image. If it sees height and width attributes, it will leave that space free while it draws the rest of the content around it. On the other hand, if it doesn’t, when the image finishes downloading, it will suddenly appear and move all the other content around accordingly.

Think of layout shifts as pushy drunk people in bars.

The same rule applies to other kinds of elements. Ads are a major contributor to CLS because a lot of ad networks are really slow and many sites download ads from multiple networks on every load. When every ad finishes loading, the page updates and content jumps around to accomodate the ad.

Dynamically injected content is a little more interesting. Let’s say that you use javascript to display the weekly forecast to your users. The weather API is significantly slower than your website so the weather finishes download last. When it finishes downloading, your javascript processes it and renders it to the user. The rest of the content jumps around to incorporate it.

Web Fonts are another key contributor to layout shift. FOIT and FOUT are the two most obvious and reported on metrics but there’s another, more insiduous problem with web fonts. The biggest problem I see is that different fonts have different character sizing, kerning and spacings, so when the browser is finished downloading the web font, it has to render content at a new line length. A couple of millimeters per line on desktop adds up to centimeters per paragraph on mobile. When character properties change dramatically, content length (in millimeters) changes as well.

Flash of invisible text and flash of unstyled text refers to the two main ways that browsers will deal with the time between when the page loads and when your web font loads. Traditional advice is we can either hide the font (FOIT) or show unstyled font (FOUT). I say fuck it, let’s see how far we can go without web fonts first. If we really need web fonts, optimize the hell out of them first. But let’s go as far as we can with common system fonts first.

Why let a problem creep in?

And finally, let’s talk about DOM updates. My ‘favourite’ example of this happens on Javascript heavy sites that do a test early on to see if a user is logged in. If not, they will download a flash and render a red or yellow ‘alert’ bar right across the top or bottom of the website. That’s if I’m lucky. Big modals that render five seconds after I can start interacting with the page put me into a near neurotic state of disappointment with website developers.

Can we stop doing that? As an industry, let’s just decide that our stupid mailing lists aren’t worth doing that to people. Why not just write really good content that people can relate to?

Preventing cumulative layout shift

Did you see the common theme in all those root causes? If content is downloaded at different times, the page has to shift to accomodate it. So it follows that if you set the content size earlier, the page will render at the proper size earlier and nothing has to shift.

In other words:

min-height:

But don’t just think about height, consider width. What happens if a heading spills over two lines? Test what happens with columns and heights in the outside elements.

Another strategy is to read documentation. A lot of CSS/Javascript frameworks have some good ways to prevent layout shifting when content downloads at different times.

Finally, look at your page composition. What do you download on every single page? What do you really have to download to display your content? Can you remove resources entirely or defer them?

Next article

Next article, we’re going to talk about first input delay (FID). First input delay measures responsiveness - it specifically measures the time between when a user does something on the page and when the browser is ready to respond.

Check out the rest of An introduction to Core Web Vitals here: