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.
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.