How to optimize for CLS when loading more content asynchronously

Andrea Verlicchi
YNAP Tech
Published in
3 min readAug 31, 2020
A “Load more” button at the end of a list of images

Cumulative Layout Shift (CLS) is an important, user-centric metric for measuring visual stability because it helps quantify how often users experience unexpected layout shifts — a low CLS helps ensure that the page is delightful.

What you might not know is:

  • CLS is measured continuously. In fact, its value is also updated while your users scroll your page, if the scroll generates some layout movement
  • CLS measurement is paused for 500ms whenever a user interaction like a click or a keyboard event occurs

Long story short, Cumulative Layout Shift measures every unexpected layout movement occurring while your users interact with the page, including while they scroll down.

When loading more content in our pages, the most common source of CLS is the page footer becoming visible for a while, then being pushed below-the-fold again by new, dynamically added content.

So how to keep CLS from growing when we need to load new content dynamically, e.g. to load a whole new page of products? Let’s analyse the two most common techniques currently used to do that:

  • Infinite scroll — users will trigger the loading of the new content just by scrolling down towards the bottom of the page
  • “Load more” button — users will have to manually trigger the loading of new content by pushing a button. This is generally used when you want your users to be able to reach the footer.

When using infinite scroll

If you use the infinite scroll technique to load additional content onto your web page and you don’t want it to generate CLS, you mustn’t allow the footer to enter the visible portion of the page (the viewport).

You can do so by appending a set of placeholders (or page skeleton) before your users reach the footer, then replacing it with the content as it arrives.

Use the Core Web Vitals extension for Chromium browsers to see how CLS is impacted in the following demos:

Here’s the code of the A2 demo on Codepen.

Demo A2: Skeleton → Good for CLS

When using a “Load more” button

If you use a “Load more” button to load additional content onto your web page and you don’t want it to generate CLS, you have two options:

  1. append new content within 500 ms from the user interaction (the click on the “Load more” button), e.g. by prefetching new content before users actually click
  2. append a set of placeholders (or page skeleton) as soon as users click, then replace it with new content as soon as it’s done fetching

Use the Core Web Vitals extension for Chromium browsers to see how CLS is impacted in the following demos:

Here’s the code of the B2 and B3 demos on Codepen.

Demo B2 — No skeleton, but content is injected immediately
Demo B3 — Skeleton, content is injected whenever it’s ready

A real-world example

Besides the demos, you can check how we optimized for CLS on Isabel Marant’s product listing page, where new products are retrieved while users scroll down, but they are appended to the page only when users click.

This technique improves user experience by quickly showing the new page, leaves the website accessible to users browsing with assistive technology (AT), and allows users to check the footer, without generating any Cumulative Layout Shifting.

Conclusion

The golden rule to avoid generating CLS is:

Don’t move any visible portion of the page while users scroll down: you’re allowed to do that only after a user interaction, and within 500 milliseconds.

Hope you enjoyed this guide. Add your clap if you did!

--

--

Andrea Verlicchi
YNAP Tech

Web performance consultant at Cognizant Netcentric, formerly YOOX NET-A-PORTER. Technical writer, speaker at web conferences.