Web Performance & Standards
What is CLS?
CLS, Cumulative Layout Shift, is a Core Web Vitals metric that measures the visual stability of a web page during and after loading, quantifying how much visible page content unexpectedly moves or shifts as the page loads and resources arrive. CLS captures the frustrating experience of trying to read or interact with a page while its layout reorganises around you, text jumping down as an image loads above it, a button moving just as you tap it, an article shifting as an advertisement appears.
The name describes the measurement approach, cumulative, the total accumulated impact of all unexpected layout shifts during a page visit, and layout shift, the unexpected movement of rendered elements between successive frames. CLS is expressed as a unitless score rather than a time measurement, it reflects the magnitude of visual disruption rather than a duration. A CLS score of 0 means the page has no unexpected layout shifts, perfect visual stability. A CLS score of 0.5 represents significant visual disruption.
CLS is one of three Core Web Vitals and a direct SEO ranking signal in Google’s Page Experience system. Unlike LCP and TTFB, which are affected by server performance, network conditions, and redirects, CLS is primarily a frontend engineering concern. CLS is caused by how pages are built, whether images have declared dimensions, whether space is reserved for late-loading content, whether fonts are loaded without causing text reflow, rather than by server response times or network infrastructure.
Understanding CLS is important for the complete picture of page quality that influences search rankings, while redirect management primarily affects LCP through TTFB overhead CLS represents the visual stability dimension of page experience that operates independently of infrastructure performance.
How CLS is calculated
CLS is calculated through a specific formula that measures both the fraction of the viewport affected by a shift and how far elements moved, producing a score that reflects the visual impact of each shift.
Layout shift score formula, each individual layout shift contributes a score calculated as:
Layout Shift Score = Impact Fraction × Distance Fraction
Impact fraction, the fraction of the viewport area that was affected by the layout shift. If an element that occupied 50% of the viewport moved unexpectedly the impact fraction is 0.5. If the element and everything it displaced combined to affect 75% of the viewport the impact fraction is 0.75.
Distance fraction, the maximum distance any element moved during the shift, expressed as a fraction of the viewport’s largest dimension, typically height. An element that moved 25% of the viewport height contributes a distance fraction of 0.25.
Combined score calculation, an element that moves 50% of the viewport height and affects 60% of the viewport area produces an individual layout shift score of 0.5 × 0.6 = 0.30.
Session windows and CLS aggregation, CLS aggregates individual layout shift scores using session windows, groups of shifts that occur within 5 seconds of each other with gaps of no more than 1 second between successive shifts. The CLS score for a page visit is the largest session window score, not simply the sum of all shifts. This windowed approach prevents pages with occasional large shifts from being penalised equally with pages that have continuous small shifts.
The reported CLS score is the maximum of all session window scores observed during the page visit, encouraging pages to eliminate their worst layout shift clusters rather than simply averaging.
CLS thresholds
Google defines three performance categories for CLS, determining how a page is assessed in the ranking system.
Good, under 0.1, pages with CLS under 0.1 are considered visually stable. To achieve a good CLS assessment 75% of real user visits, measured by Chrome User Experience Report, must have CLS under 0.1. Google recommends targeting 0.1 as the performance goal.
Needs Improvement, 0.1 to 0.25, pages with CLS between 0.1 and 0.25 have noticeable layout shifts that disrupt the reading or interaction experience. These pages should be prioritised for visual stability improvements.
Poor, over 0.25, pages with CLS over 0.25 have severe layout instability, content moves significantly and frequently during loading. Poor CLS creates a genuinely frustrating experience, users may click the wrong element when a shift occurs during interaction.
What causes layout shifts
Layout shifts are caused by specific technical patterns, understanding the causes enables targeted fixes.
Images without declared dimensions, the most common and impactful cause of CLS. When an <img> element does not have explicit width and height attributes, or equivalent CSS, the browser does not know how much vertical space to reserve for the image before it loads. The browser renders the surrounding text first, flowing it as if no image were present, then when the image arrives the browser inserts it and pushes all the text below downward. The text shift is a layout shift that contributes to CLS.
The fix is simple, always declare width and height attributes on all <img> elements:
Modern CSS also supports aspect-ratio for maintaining proportional dimensions in responsive contexts, preventing layout shifts when image dimensions are specified in relative units.
Advertisements and embeds without reserved space, advertisement slots often have variable dimensions, different ads have different heights. When the ad loads it may be taller or shorter than the space available, shifting surrounding content. Reserving fixed minimum dimensions for advertisement slots prevents this, even when the ad does not load the space is reserved.
Similarly embedded content, social media embeds, video embeds, third-party widgets, may load at different sizes than the initial placeholder. Using fixed-size containers with CSS overflow handling prevents embeds from causing layout shifts.
Web fonts causing FOUT and FOIT, Flash of Unstyled Text and Flash of Invisible Text occur when web fonts load after the browser has already rendered text in a system fallback font. When the web font arrives the browser re-renders the text, often in a slightly different size or with different character spacing, shifting surrounding content. Two approaches address font-related CLS:
font-display: optional, only uses the web font if it is available immediately from cache, falling back to the system font permanently for this page visit if the web font is not instantly available. Eliminates font swap shifts entirely but means web fonts may not be used on first visits.
size-adjust and ascent-override, CSS font metric properties that adjust the fallback font’s dimensions to match the web font, making the fallback render at the same size as the web font, eliminating the shift when the web font arrives.
Dynamically injected content, content inserted above existing content after the initial render, through JavaScript after page load. A notification banner that appears at the top of the page after load shifts all page content down. A cookie consent banner that inserts above the navigation pushes the navigation and all content below it down. Techniques to avoid this include reserving space for dynamic content with CSS min-height declarations or positioning dynamic content in a way that does not affect surrounding layout, fixed positioning rather than in-flow positioning.
CSS animations that trigger layout, animations that modify properties causing layout recalculation, width, height, top, left, margin, padding, trigger layout shifts. Animations should use transform and opacity instead, these properties are composited by the browser without triggering layout, enabling smooth animations that do not cause CLS.
CLS and redirects
CLS is one Core Web Vitals metric that redirects do not directly affect. CLS is measured on the destination page after it loads, the redirect is a pre-load event that completes before any page content begins rendering. The destination page’s CLS is entirely determined by how that page is built, its image dimension declarations, font loading strategy, advertisement slot sizing, and dynamic content injection patterns.
However there is an indirect relationship worth understanding, redirect chains that add significant TTFB overhead may interact with CLS in specific scenarios:
Late resource loading from slow TTFB, when high TTFB delays the initial HTML the browser has less time to discover and begin loading resources before the user might interact with the page. If images load very late, after the user has already begun reading, their load creates larger apparent layout shifts because the user has already established reading position before the shift occurs. Fast TTFB means resources load earlier, when content is more likely still loading rather than already being read.
Font loading timing, slow TTFB combined with late font loading may cause fonts to arrive and trigger text reflow after the user has begun reading, creating a perceptible CLS experience even if the shift score itself would be the same. Faster TTFB means the font swap, if it occurs, happens earlier in the loading sequence before the user has settled into reading the page.
These indirect effects are secondary, CLS improvement is primarily a frontend engineering concern that operates independently of infrastructure performance.
Measuring CLS
CLS measurement requires capturing real user experiences or accurately simulating them, individual point-in-time measurements may miss layout shifts that occur at different stages of loading.
Chrome DevTools Performance panel, the most detailed CLS diagnostic tool. Recording a performance trace in the Performance panel captures all layout shifts, showing exactly when each shift occurred, which elements shifted, and what caused the shift. The Experience track in the performance timeline shows CLS events as red markers. Clicking a CLS event reveals which elements shifted and by how much, enabling precise diagnosis of CLS causes.
Lighthouse, Google’s automated quality tool, integrated into Chrome DevTools and PageSpeed Insights, measures CLS in controlled lab conditions. Lighthouse provides a CLS score alongside diagnostics identifying which elements caused layout shifts. The Avoid large layout shifts audit shows specific CLS-causing elements.
Web Vitals Chrome extension, a browser extension that displays real-time Core Web Vitals measurements including CLS for any page, showing the current CLS score as the page loads and updating as layout shifts occur. Useful for quick CLS checks during development.
Search Console Core Web Vitals report, aggregates CrUX field data, real user measurements, for all URLs on a site. Shows which pages have poor or needs-improvement CLS based on actual user experiences, prioritising the pages with the most significant real-world CLS issues.
Layout Instability API, the browser API that powers CLS measurement in JavaScript, directly accessible in web application code:
The hadRecentInput check excludes shifts caused by user interaction, only unexpected shifts are accumulated.
Improving CLS
CLS improvement is methodical, identifying the specific causes through measurement and applying targeted fixes.
Audit all images for dimension declarations, crawl the site and identify all <img> elements missing width and height attributes. Add explicit dimensions to all images. For responsive images that scale with the viewport use CSS aspect-ratio in conjunction with width: 100%:
Reserve space for advertisements, implement minimum size containers for all advertisement slots, using CSS min-height to ensure space is reserved even when no ad loads:
Implement font loading strategy, choose a font loading strategy that eliminates swap-related layout shifts. For most sites font-display: optional provides the best CLS outcome, using the system font for first visits and the web font for subsequent cached visits without any swap-related shift.
Audit dynamic content injection, identify all JavaScript that injects content into the page after load. For content that cannot be avoided ensure it is positioned using fixed positioning, position: fixed, or appended at the bottom of content rather than inserted above existing content. Use CSS min-height reservations for containers that will receive dynamic content.
Use CSS transforms for animations, replace layout-triggering CSS animations with transform-based alternatives: