---
title: "CLS in WordPress: stop layout shifts"
id: "514"
type: "post"
slug: "cls-wordpress"
published_at: "2026-10-06T15:13:52+00:00"
modified_at: "2026-10-06T15:13:52+00:00"
url: "https://danielpazwp.com/cls-wordpress/"
markdown_url: "https://danielpazwp.com/cls-wordpress.md"
excerpt: "The usual sources of layout shift on WordPress sites, from images without dimensions to font swaps and banners, and how to find and fix each one."
taxonomy_category:
  - "Performance"
---

[Performance](https://danielpazwp.com/category/performance/)
7 min read

# CLS in WordPress: stop layout shifts

The usual sources of layout shift on WordPress sites, from images without dimensions to font swaps and banners, and how to find and fix each one.

Published **06/10/2026**7 min read

[Written byDaniel PazDaniel Paz has worked on the web for more than 14 years and has focused on WordPress since 2016. He is CEO and founder of WebOption, creator of WP Alta Performance (Brazil’s reference channel on WordPress optimization) and has shipped WordPress for Globo, Shell, Endeavor, Estratégia Concursos and Brazil’s Federal Government. He speaks at WordCamp Brazil, WordCamp Canada and WordCamp US, TDC and PHP Conference Brazil.](https://danielpazwp.com/author/daniel-paz/)

To reduce CLS in WordPress, reserve space for everything before it loads (images, embeds, ad slots, banners) and stop web fonts and late CSS from reflowing the page. CLS (Cumulative Layout Shift) scores unexpected movement of visible content and reports the largest burst of shifts during the visit. Google rates 0.1 or less at the 75th percentile as good and more than 0.25 as poor. On WordPress the usual sources are images without `width` and `height` in theme templates, font swaps, cookie and promo bars inserted above the header, ads and embeds, and optimization plugins that delay or strip CSS.

CLS is the Core Web Vital that annoys people most. You go to tap a link and the page moves, and you tap an ad instead. It is also the one with the most mechanical fixes. Once you know which element moves, the fix is usually a few lines of HTML or CSS. For the other two metrics and the overall fix order, see [Core Web Vitals for WordPress: the complete guide](https://danielpazwp.com/core-web-vitals-wordpress/)
.

## How is CLS calculated?

Each layout shift gets a score from two numbers: how much of the viewport the moving elements affect (impact fraction) and how far they move relative to the viewport (distance fraction). Shifts are grouped into session windows. A window ends after one second without shifts, or after five seconds in total. CLS is the score of the worst window, not the sum of the whole visit.

Two details explain most confusion about CLS:

- Shifts within 500 milliseconds of a user input (a click, tap or key press) are excluded. Opening an accordion when the user taps it is fine. Scrolling is not an input for this rule.
- CLS is measured during the whole visit in the field, but Lighthouse only watches the load. Shifts caused by lazy content, ads that load while scrolling or sticky headers that change height show up in CrUX and not in your lab test.

That second point is why I never close a CLS issue based on Lighthouse alone. More on the difference in [Core Web Vitals field data vs lab data](https://danielpazwp.com/core-web-vitals-field-data-vs-lab-data/)
.

## What causes layout shifts in WordPress?

| Cause | Where it comes from | Fix |
| --- | --- | --- |
| Images without dimensions | Theme templates, builder widgets, custom loops | Output width and height, or set aspect-ratio in CSS |
| Web font swap | Fonts with different metrics from the fallback font | Metric overrides on the fallback, preload the main font, consider font-display: optional |
| Banners inserted at the top | Cookie consent, promo bars, notification plugins | Overlay them with fixed positioning, or render the space in the server HTML |
| Ads without reserved space | Ad scripts injecting variable-size creatives | Fixed min-height per slot, sized to the most common creative |
| Embeds | YouTube, social posts, maps, iframes | Responsive embed wrappers with a set aspect ratio |
| Late or stripped CSS | “Remove unused CSS”, delayed CSS, async stylesheets | Test on each template; keep the styles for the first screen in the critical path |
| Sliders and carousels | Height set only after the script runs | Fixed height or aspect ratio before initialization |
| Animations on layout properties | Animating top, left, height or margin | Animate transform and opacity instead |

WordPress handles part of the image problem for you. Core adds `width` and `height` to images in post content, and `wp_get_attachment_image()` outputs them too. The shifts I find in audits usually come from code that bypasses both: theme templates that build `img` tags by hand, builder widgets, and plugins that inject images with JavaScript.

For embeds, block themes and classic themes that declare `add_theme_support( 'responsive-embeds' )` get core styles that keep the aspect ratio of embedded videos. Without that support, an embed can load at one size and then resize.

## How do I find the element that shifts?

- In PageSpeed Insights, the Lighthouse audit for large layout shifts lists the elements that moved during the lab load.
- In the Chrome DevTools Performance panel, recorded layout shifts appear in their own track, and selecting one highlights the element.
- The attribution build of the web-vitals library reports the element behind the largest shift from real visits, including shifts that happen after load.

Field attribution matters most for CLS, because many shifts only happen after the user scrolls. If Lighthouse shows a CLS of 0 and Search Console says your mobile pages are poor, the shift happens later in the visit.

## How do I fix font-related CLS in WordPress?

When a web font replaces the fallback font, text reflows if the two fonts have different widths or line heights. Every line break can move, and everything below it moves too.

- Self-host the font instead of loading it from a third-party CSS file. Block themes can register fonts in `theme.json` under `fontFace`, including the `fontDisplay` value, and since WordPress 6.5 the Font Library installs fonts on your own server.
- Preload the one or two font files used above the fold.
- Adjust the fallback font with `size-adjust`, `ascent-override` and `descent-override` in an `@font-face` rule, so it takes up the same space as the web font.
- Use `font-display: optional` when the brand can accept the fallback on a slow first visit. It avoids the late swap entirely.

Font loading also affects LCP when the LCP element is a heading, so this work often helps both metrics. See [how to improve LCP in WordPress](https://danielpazwp.com/lcp-wordpress/)
 for the loading side.

## Can caching and optimization plugins cause CLS?

Yes, and often. Features that remove unused CSS, delay CSS until interaction, or load stylesheets asynchronously can render the page before its styles arrive. The browser paints unstyled content, the styles land, and everything jumps. Generated critical CSS that misses a component does the same.

Test these features on every template type, on a real phone, with a cold cache. If one template breaks, exclude its styles from the optimization instead of turning the feature off everywhere. The same plugins can also hurt responsiveness when they delay scripts, which I cover in [how to fix INP in WordPress](https://danielpazwp.com/inp-wordpress/)
.

## Why do sticky headers and cart counters shift the page?

A header that switches from static to fixed when the visitor scrolls leaves the document flow, and the content below jumps up by the header’s height. Make the header sticky from the start with `position: sticky`, or keep a placeholder of the same height in its place. Small elements shift too. A header cart count or a greeting that JavaScript fills in after load can change the width of everything next to it. Give these elements a fixed width, or render their final content in the HTML when the page cache allows it.

## Does the back/forward cache help CLS?

When a visitor goes back or forward, Chrome can restore the page from the back/forward cache (bfcache) instantly, with no new load and so no new load shifts. Pages that send `Cache-Control: no-store` or use `unload` event handlers can lose that eligibility. DevTools has a back/forward cache test in the Application panel that tells you whether a page qualifies and why not.

## How do I verify a CLS fix?

Reproduce the shift in DevTools, apply the fix and confirm the shift is gone from the layout shift track. Then watch real user data for the template, including scroll behavior. CrUX needs 28 days to fully reflect the change in PageSpeed Insights and Search Console.

## Still seeing layout shifts?

If your CLS fails in the field and you can’t reproduce it, the shift is probably happening after load, in a component nobody tests. I find it in field data and trace it back to the theme, plugin or script that causes it. Learn more about [my Core Web Vitals audits for WordPress](https://danielpazwp.com/core-web-vitals-expert/)
.

[Work with Daniel](https://danielpazwp.com/#book)
[More in Performance](https://danielpazwp.com/category/performance/)

[About the authorDaniel Paz has worked on the web for more than 14 years and has focused on WordPress since 2016. He is CEO and founder of WebOption, creator of WP Alta Performance (Brazil’s reference channel on WordPress optimization) and has shipped WordPress for Globo, Shell, Endeavor, Estratégia Concursos and Brazil’s Federal Government. He speaks at WordCamp Brazil, WordCamp Canada and WordCamp US, TDC and PHP Conference Brazil.Author page](https://danielpazwp.com/author/daniel-paz/)

## Related articles

[All articles](https://danielpazwp.com/blog/)

[Performance Oct 2026Headless WordPress: when it makes sense and when it does not](https://danielpazwp.com/headless-wordpress/)
[Performance Oct 2026How to speed up Elementor: the fixes that matter](https://danielpazwp.com/speed-up-elementor/)
[Performance Oct 2026Elementor vs Gutenberg performance: what the architecture means](https://danielpazwp.com/elementor-vs-gutenberg-performance/)
