How to Fix Cumulative Layout Shift (CLS)
- Difficulty
- Easy to moderate
- You need
- PageSpeed Insights, Chrome DevTools
- Optional
- Access to page templates and CSS
On this page
To fix Cumulative Layout Shift, find the elements that move while the page loads, then give the browser enough information to reserve their space before they arrive. Most shifts come from images and embeds without dimensions, banners inserted above content, and web fonts that swap in at a different size. Good CLS is 0.1 or less. This guide is part of our website design best practices guide.
You'll need PageSpeed Insights and Chrome DevTools, plus access to your templates and CSS for the fixes. For background on the metric itself, see Core Web Vitals.
What counts as a layout shift
A layout shift happens when a visible element changes its starting position between two frames without the visitor asking for it. Each shift gets a score based on how much of the viewport moved and how far it moved.
Shifts are grouped into bursts, called session windows. A window closes after one second with no shifts, or after five seconds in total. The page's CLS is the score of its worst burst, not the sum of every shift in the visit, so one bad moment can decide the result.
Two kinds of movement don't count. Shifts within 500 milliseconds of a tap, click or key press are expected and left out. Animations that use CSS transform don't move other elements, so they don't count either. Scrolling isn't treated as input, so content that jumps during a scroll still adds to the score.
Common causes of layout shift
Most shifts on business sites trace back to a short list of causes. Knowing them makes the DevTools recording much quicker to read.
| Cause | Where it shows up | Usual fix |
|---|---|---|
| Images or video without dimensions | Blog posts, galleries, hero areas | Set width and height, or aspect-ratio |
| Embeds and iframes | Maps, videos, social posts, booking widgets | Reserve space with min-height |
| Ads and promos inserted late | Top of page, between paragraphs | Fixed slots sized before they load |
| Banners added above content | Cookie notices, announcement bars | Overlay at the bottom, or reserve space |
| Web font swap | Headings and body text | Fallback font metric overrides |
| Animating layout properties | Menus, accordions, hover effects | Animate transform instead |
Steps
- Check field CLS and find the affected templates.
Open the Core Web Vitals report in Search Console, or the field section of PageSpeed Insights, and see which URL groups have poor or needs improvement CLS. Shifts usually come from a template, so a fix on one page type often repairs hundreds of URLs. Note whether mobile, desktop or both are affected, because layouts differ.
- Record the shifts and find the element that caused them.
In Chrome DevTools, record a page load in the Performance panel and open the Layout shifts track. Each shift shows an animation of what moved. Lighthouse lists the elements that shifted, but these are often the ones pushed down, not the cause. Look for the element inserted or resized just above them.
- Give every image and video dimensions.
Add width and height attributes to every img and video element. Browsers use them to work out the aspect ratio and reserve the right space before the file loads, even when CSS makes the image responsive. For responsive embeds and images without fixed dimensions, set the CSS aspect-ratio property. Our guide to image optimization covers sizing in more detail.
- Reserve space for embeds, ads and late content.
Content that loads after the first paint needs a placeholder of roughly the right size. Use min-height rather than a fixed height, so the box can still grow if the content or the text inside it is larger:
css.map-embed { aspect-ratio: 16 / 9; width: 100%; } .booking-widget { min-height: 28rem; } .promo-slot { min-height: 15.625rem; } - Never insert content above what's already on screen.
Cookie notices, announcement bars and "you might also like" blocks often push the page down after it has rendered. Show them as an overlay fixed to the bottom of the screen, or reserve their space in the initial layout. If new content must appear in the flow, add it below the viewport or after the visitor asks for it.
- Match your fallback font to your web font.
When a web font replaces the fallback, lines can rewrap and push content down. Pick a fallback with similar proportions, then fine-tune it with the size-adjust, ascent-override and descent-override descriptors. Preload the one or two fonts used above the fold. We cover font-display choices in web font loading best practices.
- Animate with transform, not layout properties.
Animating top, left, width, height or margin forces the browser to recalculate layout and moves neighbouring elements. Animating transform, using translate or scale, doesn't affect other elements and doesn't count toward CLS. Rebuild slide-in menus, expanding cards and hover effects this way, and keep the motion optional:
css.menu { transform: translateY(-100%); transition: transform 0.2s; } .menu.is-open { transform: translateY(0); } @media (prefers-reduced-motion: reduce) { .menu { transition: none; } } - Make pages eligible for the back/forward cache.
When a visitor goes back to a page, the bfcache can restore it exactly as they left it, with no reload and no shifts. Pages can lose eligibility through things like unload event handlers. Chrome DevTools has a back/forward cache test in the Application panel that lists what's blocking it.
- Re-test, including scrolling and interactions.
Record the load again and confirm the shifts are gone. Then scroll the full page and open menus, tabs and accordions, because lab tests mostly measure the initial load. Field data updates over the following weeks. In Search Console, start a validation once the fix is live.
Layout stability is easiest to get right when it's planned into the templates from the start. If you'd rather have that handled, our in-house web team designs and develops sites with performance built in.
Stable layouts that still work for everyone
A stable layout helps people who are easily disoriented, people using screen magnifiers and people with limited fine motor control, who are most affected when a button moves under their finger. But some CLS fixes can create new barriers if they're done carelessly.
Reserve space, don't lock it. A box with a fixed pixel height stops a shift, but it can clip or overlap text when someone zooms in. WCAG's Resize Text criterion asks that text can be enlarged to 200 percent without losing content. Its Text Spacing criterion expects content to cope when people increase line, letter and word spacing. That's why we prefer min-height and aspect-ratio over fixed heights: the space is reserved, but the box can still grow.
Keep reflow working. WCAG's Reflow criterion asks that content works at a width of 320 CSS pixels without scrolling in two directions. Placeholders sized in fixed pixel widths break that. Size them in relative units, and test reserved space at a narrow width and at high zoom.
Don't cover the focused element. Moving a cookie banner to a fixed overlay fixes CLS, but a fixed banner or sticky header can hide the link a keyboard user has just tabbed to. WCAG 2.2's Focus Not Obscured (Minimum) criterion addresses this. Add scroll padding equal to the header's height, and make banners easy to dismiss.
Announce changes instead of pushing content. Messages such as "added to cart" or form errors that appear above the content cause shifts and may never reach screen reader users. A status message in a reserved area, announced with an ARIA live region, fixes both. WCAG's Status Messages criterion covers the announcement part.
Troubleshooting
CLS is poor in the field but zero in the lab
Cause: lab tests measure the initial load in one simulated session. Real visitors scroll, accept or ignore cookie banners, see ads that differ by visit and open pages from links that trigger different content. Shifts that happen after the load, or only for some visitors, never appear in the lab run, but they do appear in field data.
Fix: reproduce a real visit. Record a Performance trace while scrolling the whole page, with the cache cleared and any consent banner showing. Repeat at a phone width. Check pages that load personalised or ad content more than once, because each visit may differ. If the cause still isn't clear, collect your own field data with a small script that reports layout shifts and the elements involved, so you can see what moves for real visitors.
The page shifts when a cookie or promo banner appears
Cause: the banner is inserted at the top of the page after the content has rendered, so everything below moves down. Banners are often added by a third-party script that loads late, which makes the shift both large and unpredictable. On mobile it may push the whole first screen out of view.
Fix: display the banner as an overlay fixed to the bottom of the screen, so it doesn't push the content. If it must sit at the top, reserve its height in the initial HTML and CSS, and collapse the space only after the visitor dismisses it. Check that the overlay doesn't cover focused links or form fields, that it can be closed with a keyboard, and that focus returns to a sensible place afterwards.
Text jumps when the web font loads
Cause: the browser first renders text in a fallback font, then swaps in the web font when it arrives. If the two fonts have different widths or line heights, lines rewrap and the content below moves. Large headings set in a wide display font show this most, and the shift is worse on slow connections where the swap happens late.
Fix: choose a fallback font with similar proportions, then match it more closely with size-adjust and the ascent and descent overrides in an @font-face rule for the fallback. Preload the main font so it arrives before first paint more often. If the font is decorative and a short wait isn't worth a shift, `font-display: optional` uses the web font only if it's ready in time.
Common questions
Does a layout shift count if the visitor caused it?
Usually not. Shifts that happen within 500 milliseconds of a tap, click or key press are flagged as recent input and left out of CLS, because people expect the page to respond. Scrolling, dragging and pinch-zoom don't count as recent input, though. So content that jumps while someone scrolls, such as a header that changes height, still adds to the score.
Is a CLS score of zero realistic?
On many pages, yes, especially simple content pages with sized images and no late-loading embeds. It isn't required, though. The good threshold is 0.1 or less at the 75th percentile, so small, rare shifts won't fail a page. Aim for zero on templates you control, then focus on any shift large enough to make someone lose their place or tap the wrong thing.
Do CSS animations hurt CLS?
Only if they change layout. Animating properties such as top, left, width, height or margin moves other elements and can count as a layout shift. Animating transform, such as translate or scale, is handled by the compositor and doesn't affect other elements, so it doesn't count toward CLS. Keep motion optional for visitors who have asked their device to reduce it.