Two of Google’s three Core Web Vitals — Cumulative Layout Shift (CLS) and
Interaction to Next Paint (INP) — are frequently misunderstood, yet both
directly impact your search rankings and are flagged regularly in Google
Search Console.
This guide covers both metrics: what they measure, how to diagnose failures,
and how to fix them on WordPress, Shopify, or any CMS.
Already working on your LCP? See our
LCP fix guide for the
third Core Web Vital.
Part 1: Cumulative Layout Shift (CLS)
What Is CLS?
CLS measures how much your page’s content unexpectedly moves while loading.
Have you ever tried to click a button on a mobile page, only to have an image
load above it and push the button down — so you accidentally tap something
else? That is layout shift, and Google measures it.
Google’s [2026] CLS targets:
- Good: Under 0.1
- Needs improvement: 0.1 – 0.25
- Poor: Over 0.25
Poor CLS is both a ranking penalty and a user experience disaster — it causes
mis-taps, accidental purchases, and frustrated users who leave.
How to Find Your CLS Score
In Google Search Console:
- Go to GSC → Core Web Vitals → Mobile report
-
Click into “Poor” pages — GSC will show you the specific CLS issue type
-
Common issue labels: “Layout shift from unsized media”, “Layout shift from
web fonts”, “Layout shift from dynamically injected content”
In Chrome DevTools:
- Open your page in Chrome → press F12 → go to the Performance tab
- Click record, let the page load, then stop recording
- In the Experience section, layout shift events appear as red blocks
-
Click each block to see which element caused the shift and where it came
from
In PageSpeed Insights:
- The CLS value appears under Lab Data
-
The Diagnostics section lists which specific elements are causing layout
shift
The 5 Most Common CLS Causes and Fixes
Cause 1: Images and Videos Without Defined Dimensions
The most common cause of CLS. When the browser starts loading your HTML, it
does not know how large an image will be until the image file itself starts
downloading. Without pre-defined dimensions, the browser assigns the image
zero height — then suddenly jumps the entire page layout down when the image
loads.
Fix: Always define width and height attributes on every
<img> tag:
<!-- WRONG — browser does not know the height until image loads -->
<img src="product.webp" alt="Product">
<!-- RIGHT — browser reserves the correct space immediately -->
<img src="product.webp" width="800" height="600" alt="Product">
For responsive images, also add CSS:
img {
max-width: 100%;
height: auto;
}
This is the single highest-impact CLS fix for most websites and takes minutes
to implement.
For WordPress: Install the “Specify Image Dimensions” feature in your caching
or optimisation plugin. WP Rocket handles this automatically. For individual
images, ensure you set dimensions in the media editor.
Cause 2: Ads, Embeds, and Iframes Without Reserved Space
Advertisements, social media embeds, and iframes often have unknown dimensions
until they load. When they appear mid-page, they push all content below them
downward — causing significant CLS.
Fix: Reserve space for ads and embeds using a CSS wrapper
with a fixed aspect ratio:
.ad-container {
width: 100%;
min-height: 250px; /* Reserve space for the ad */
}
For Google AdSense, use the “Auto ads” format’s size hints feature to tell the
browser the ad dimensions before loading.
For social media embeds (Twitter/X, Instagram, YouTube), use aspect-ratio CSS:
.video-wrapper {
aspect-ratio: 16 / 9;
width: 100%;
}
Cause 3: Dynamically Injected Content Above Existing Content
If JavaScript inserts content (a banner, cookie consent bar, promotional
notice, chat widget, newsletter popup) above already-visible content after the
page has loaded, everything below shifts down.
Fix:
-
Cookie consent bars: Use a consent manager that reserves space for the bar
in the initial HTML rather than injecting it after load. Cookiebot and GDPR
Cookie Consent both have CLS-safe implementations.
-
Promotional banners: Ensure banners are part of the initial HTML, not
JavaScript-injected. If they must be JS-injected, insert them below the
fold.
-
Chat widgets: Most chat widget scripts insert a fixed-position button that
does not cause CLS. If yours does cause shift, move the chat widget script
to load after the page is fully interactive.
Cause 4: Web Fonts Causing FOUT (Flash of Unstyled Text)
When a custom font loads and replaces a fallback system font, the different
glyph widths can cause text to reflow — pushing other content elements around
on the page.
Fix:
Cause 5: Animations That Move Existing Content
CSS or JavaScript animations that move page elements (sliding content in from
the side, expanding accordions, animated headers) contribute to CLS if they
affect elements that push other content.
Fix: Use CSS transform and opacity for animations instead of
properties that affect layout (margin, padding, height, top, left). Transforms
are GPU-accelerated and do not trigger layout recalculation:
/* CAUSES CLS — changes layout */
.animate { margin-top: 0; animation: slideDown 0.3s; }
@keyframes slideDown { from { margin-top: -50px; } to { margin-top: 0; } }
/* NO CLS — transform does not affect layout */
.animate { transform: translateY(0); animation: slideDown 0.3s; }
@keyframes slideDown { from { transform: translateY(-50px); } to { transform: translateY(0); } }
Part 2: Interaction to Next Paint (INP)
What Is INP?
INP replaced FID (First Input Delay) as a Core Web Vital in March 2024. While
FID measured only the delay before a browser starts responding to the very
first user interaction, INP measures the full duration of every interaction
throughout the page lifecycle — from when a user taps, clicks, or types, to
when the next frame is painted.
If your page is slow to respond to button clicks, form inputs, dropdown
selections, or search queries — even after the page has fully loaded — you
will have a poor INP score.
Google’s [2026] INP targets:
- Good: Under 200 milliseconds
- Needs improvement: 200 – 500 milliseconds
- Poor: Over 500 milliseconds
Poor INP is particularly common on JavaScript-heavy pages and ecommerce stores
with complex product filtering.
How to Find Your INP Score
In Google Search Console:
- GSC → Core Web Vitals → Check for “Poor INP” entries
-
Note: INP data in GSC is collected from real users over 28 days. It may take
weeks for fixes to show in GSC reports.
In Chrome DevTools:
- Open DevTools → Performance tab → Enable “Web Vitals” checkbox
-
Interact with your page (click buttons, type in search boxes, open menus)
- The Performance trace will show INP candidates highlighted
- Look for long “Interaction” blocks
In PageSpeed Insights (field data):
-
Scroll to “Core Web Vitals Assessment” — if INP appears, it reflects
real-user data from the Chrome User Experience Report
The 5 Most Common INP Causes and Fixes
Cause 1: Long JavaScript Tasks Blocking the Main Thread
The browser’s main thread handles everything: parsing HTML, running
JavaScript, responding to user interactions, and painting pixels to screen. If
a long JavaScript task (over 50ms) is running when a user clicks, the browser
cannot respond to the click until that task completes.
How to identify: In DevTools Performance trace, look for
red-flagged “Long Tasks” — any JavaScript task over 50ms. These block user
interactions.
Fix:
-
Break long JavaScript tasks into smaller chunks using setTimeout() or
requestIdleCallback() — allowing the browser to process user interactions
between chunks
- Defer non-critical JavaScript to load after the page is interactive
-
Remove or delay third-party scripts that run long tasks (analytics, ad
scripts, tag managers loading many tags)
For WordPress: WP Rocket’s “Delay JavaScript Execution” setting prevents
third-party scripts from running until the user first interacts with the page
— significantly reducing INP.
Cause 2: Unnecessary Re-renders From JavaScript Frameworks
Sites built with React, Vue, Angular, or similar JavaScript frameworks can
suffer poor INP if component updates trigger large re-renders of the DOM. A
user clicking a button that triggers a state change should only update the
specific elements that need to change — not re-render entire sections of the
page.
Fix:
-
Use React’s useMemo and useCallback hooks to prevent unnecessary re-renders
-
Virtualise long lists (React Window, TanStack Virtual) so the DOM only
contains visible items
-
Split large React components into smaller ones so updates are localised
Cause 3: Complex Event Handlers Running Heavy Processing
If your page has event listeners that perform expensive operations
synchronously on user interactions (searching a large dataset, complex
calculations, DOM manipulations), the browser freezes until the operation
completes.
Fix:
Cause 4: Excessive DOM Size
Pages with thousands of DOM nodes (complex WordPress pages built with
drag-and-drop builders, ecommerce pages with large product grids) are slower
to update because every style change, layout calculation, and paint operation
must account for more elements.
Fix:
-
Target a maximum of 1,500 DOM nodes per page (check in DevTools → Elements
tab)
- Remove unnecessary wrapper divs introduced by page builders
-
Use CSS content-visibility: auto on off-screen sections to skip rendering
them until they scroll into view
Cause 5: Stylesheets Not Optimised for Interaction
Large CSS files with complex selectors can slow down style recalculation after
user interactions — adding to INP delay.
Fix:
-
Avoid universal selectors (*) and overly specific selectors in interactive
components
-
Use CSS custom properties (variables) for theme values — they update faster
than JavaScript-driven style changes
- Remove unused CSS (PurgeCSS for Tailwind users, UnCSS for others)
CLS and INP Fix Priority Order
Work through fixes in this order for maximum impact with minimum effort:
-
Add image dimensions to all <img> tags (CLS — takes 1–2 hours, huge
impact)
- Reserve ad/embed space with CSS min-height (CLS — 30 minutes)
-
Delay third-party JavaScript with WP Rocket or similar (INP — 15 minutes)
- Fix font loading with font-display: swap + preload (CLS — 30 minutes)
- Remove unused JavaScript (INP — ongoing)
- Fix animation properties to use transform/opacity (CLS — 1–2 hours)
-
Break up long tasks in custom JavaScript (INP — complex, developer work)
When to Get Professional Help
CLS is generally fixable by following the steps above. INP can be more complex
— especially if poor INP is caused by framework-specific re-rendering issues
or custom JavaScript — and may require a developer with performance
optimisation experience.
If your Core Web Vitals remain in the “Poor” range after implementing the
above fixes, our
WordPress speed optimisation service
includes a full CWV audit and implementation.
Get a quote here.
Related reading: