Frontend Development 16 min read

Understanding and Optimizing Cumulative Layout Shift (CLS) in Web Performance

This article explains the background, definition, calculation methods, measurement techniques, and practical optimization strategies for Cumulative Layout Shift (CLS), a key web‑performance metric, and provides JavaScript code examples for tracking and reporting CLS values.

HomeTech
HomeTech
HomeTech
Understanding and Optimizing Cumulative Layout Shift (CLS) in Web Performance

The article begins by describing the problem of unexpected layout shifts that disrupt user reading and interaction, introducing CLS (Cumulative Layout Shift) as a metric to quantify visual stability issues caused by asynchronous resource loading, dynamic element insertion, and uncontrolled ad content.

It defines CLS according to Google’s specification, explaining the 5‑second session windows, the requirement that shifts within a window be less than 1 second apart, and that the maximum session value represents the page’s CLS score.

The calculation is broken down into impact fraction and distance fraction, with formulas and illustrative examples showing how element movement and visible area affect the final CLS value.

Guidelines for acceptable CLS thresholds (≤ 0.1) are provided, along with cases where layout shifts are exempt, such as user‑initiated interactions and well‑implemented CSS transforms.

Measurement techniques are covered, including using Chrome DevTools Performance panel and a JavaScript PerformanceObserver implementation that aggregates layout‑shift entries while ignoring those with recent user input. Example code:

let clsValue = 0; let clsEntries = []; let sessionValue = 0; let sessionEntries = []; new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) { // Only consider shifts without recent user input if (!entry.hadRecentInput) { const firstSessionEntry = sessionEntries[0]; const lastSessionEntry = sessionEntries[sessionEntries.length - 1]; if (sessionValue && entry.startTime - lastSessionEntry.startTime < 1000 && entry.startTime - firstSessionEntry.startTime < 5000) { sessionValue += entry.value; sessionEntries.push(entry); } else { sessionValue = entry.value; sessionEntries = [entry]; } if (sessionValue > clsValue) { clsValue = sessionValue; clsEntries = sessionEntries; console.log('CLS:', clsValue, clsEntries); } } } }).observe({type: 'layout-shift', buffered: true});

It also introduces the web‑vitals library for easier metric collection, showing a short usage snippet:

import { onCLS } from 'web-vitals'; onCLS((metric) => { console.log(metric); });

Data collection and reporting strategies are discussed, emphasizing the importance of aligning the SDK’s initialization time with the CLS 5‑second window, handling early page hides via visibilitychange or pageHide , and choosing between XHR and navigator.sendBeacon for transmission.

The article then presents a real‑world case study where CLS was high due to delayed ad loading in a Vue SSR application; it outlines a step‑by‑step optimization plan that isolates ad rendering, uses a fixed‑size DOM placeholder, and prioritizes progressive loading to stabilize layout.

Finally, the summary highlights the broader benefits of CLS optimization, including improved SEO rankings, higher conversion rates, and overall better user experience.

frontendoptimizationJavaScriptWeb PerformancePerformanceObserverCLS
HomeTech
Written by

HomeTech

HomeTech tech sharing

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.