loading...
Cover image for Measuring Cumulative Layout Shift (CLS) in WebPageTest
Google Web Dev

Measuring Cumulative Layout Shift (CLS) in WebPageTest

rick_viscomi profile image Rick Viscomi Updated on ・3 min read

What is CLS?

Cumulative Layout Shift (CLS) is a relatively new metric to help you understand the delightfulness of the user experience. You might be reading a website when suddenly the text shifts down 100 pixels and you lose your place. That's not a delightful experience.

A graphic showing text shifting down

The value of a layout shift is the percent of the viewport that moved. So in this example perhaps 10% of the viewport shifted. If another shift of 2% happens later, the page's CLS would be 12%.

How can it be measured?

web.dev/layout-instability/api is a great resource to learn more about the API and how to use it to measure CLS. Here's their example code to calculate CLS:

// Stores the current layout shift score for the page.
let cumulativeLayoutShiftScore = 0;

// Detects new layout shift occurrences and updates the
// `cumulativeLayoutShiftScore` variable.
const observer = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    cumulativeLayoutShiftScore += entry.value;
  }
});

observer.observe({entryTypes: ['layoutShift']});

// Sends the final score to your analytics back end once
// the page's lifecycle state becomes hidden.
document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'hidden') {
    // Force any pending records to be dispatched.
    observer.takeRecords();

    // Send the final score to your analytics back end
    // (assumes `sendToAnalytics` is defined elsewhere).
    sendToAnalytics({cumulativeLayoutShiftScore});
  }
});

At the moment, the layoutShift type is only available when the API is explicitly enabled. If you're running Chrome 76 or newer, you can start it up via the command line with this flag set:

--enable-blink-features=LayoutInstabilityAPI

Measuring CLS in WebPageTest

WebPageTest (WPT) is a popular tool for controlled measurements of web performance stats. Let's take a look at how we can configure it to record CLS.

Choosing the right browser

WPT supports many browsers from many locations around the world. For this test to work, we need a newer version of Chrome that supports the LayoutInstabilityAPI Blink feature. Since WPT's default version of Chrome is on version 75 at this time of writing, we'll select Chrome Canary (version 77), which is available from the Dulles, VA test location.

Setting the command line flag

Under the advanced settings "Chromium" tab there's a field to provide command line options.

Measuring CLS as a custom metric

Custom metrics are snippets of JavaScript that execute as the web page test is wrapping up. The syntax is to give it a name in [name] format on the first line, followed by a script with a single return value. Here's a custom metric to measure CLS:

[CumulativeLayoutShift]
return new Promise(resolve => {
  var CLS = 0;
  new PerformanceObserver(list => {
    list.getEntries().forEach(entry => {
      if (entry.hadRecentInput) return;
      CLS += entry.value;
    });
    resolve(CLS);
  }).observe({type: "layout-shift", buffered: true});
});

Side note: Astute WPT mega-pro power users reading this post are objecting to this script because it returns a promise, and custom metrics only support synchronous code. Not anymore! As of literally a couple hours ago, WPT now supports async custom metrics!

This script will resolve to the CLS value for the test page, whose layout shifts have been saved to a buffer.


Ok! So with those options configured, you're ready to enter the URL of the page you want to test and run it. You can find the results on the Custom Metrics page.

For this page, the CLS is 0.3. It's a page I built, with a large part of its UI dynamically rendered from a script, so ~30% checks out.

To visualize this, we can use the filmstrip view, which shows us what the page looked like while it loaded. In this case it was blank for half a second, then the entire thing rendered. It's not clear where the layout shift is, but it could have happened in a matter of milliseconds. It isn't necessarily a poor user experience if the layout shift happens so close to the start of rendering, so that might be a case for tweaking the CLS algorithm.

Wrapping up

CLS is still a very new metric, so if you do start using it, please leave any feedback on the Layout Instability API GitHub repository.

Posted on by:

rick_viscomi profile

Rick Viscomi

@rick_viscomi

I work on web transparency projects like the HTTP Archive and Chrome UX Report. I work towards a faster, better web for everyone.

Google Web Dev

Collected thoughts and posts on web development from the @ChromiumDev team.

Discussion

markdown guide
 

I want to check the value for my site miniimagesvideos.com/
I run the site against developers.google.com/speed/pagesp.... Field value is coming as 0.26, while the lab value is coming as 0.0. I have embed the script in my html pages and keep getting the value as 0. Is there any site which can measure accurately

 

This is a great question and one of the challenges of measuring CLS in the lab.

Field data is inclusive of all of the actions users take on the website like scrolling and interacting with buttons. CLS may be occurring in these kinds of scenarios that lab tools like WebPageTest and Lighthouse don't currently simulate by default. With CLS gaining popularity as a Core Web Vital metric, I'd love to see lab tools incorporate more user-like behaviors to be comparable with field data.

 

This was quite helpful and well documented. Thank you!

 

Great tutorial! It helped me a lot today! Well done!

 

Thanks, I'm glad to hear that!