Core Web Vitals Fixes That Actually Move the Needle in 2026

Fix INP first, since it replaced FID in March 2024 and is where most sites fail now. Keep interactions under 200ms by breaking up long JavaScript tasks, batching your DOM reads and writes, and yielding to the main thread. Then tackle LCP and CLS.
Part of the complete web design guide.
On this page
- 1. Fix INP before you touch anything else
- 2. Stop shipping JavaScript you don’t use
- 3. Serve images in the right format and the right size
- 4. Preconnect to the domains you actually depend on
- 5. Self-host your fonts and subset them
- 6. Kill layout shift from ads, embeds, and cookie banners
- 7. Measure from the field, not just Lighthouse
- What to do first
- FAQ
- Do Core Web Vitals still affect rankings in 2026?
- Is FID still a thing?
- How long until I see changes after fixing something?
Most Core Web Vitals advice you’ll find online is either outdated or written to sell you a plugin. The metrics Google actually uses changed in March 2024 when INP replaced FID, and a lot of “fixes” people still repeat are aimed at a metric that no longer exists. Here’s what’s worth your time in 2026, with code you can actually run.
I’ll skip the “why performance matters” speech. You already know slow sites lose traffic. Let’s get into the seven fixes that move real scores.
1. Fix INP before you touch anything else
Interaction to Next Paint is where most sites fail now. It measures the delay between a user’s tap or click and the next frame the browser paints. Google’s good threshold is under 200ms at the 75th percentile. A single long JavaScript task on your main thread will blow that number out.
The usual culprit is event handlers doing too much. If you’re running layout reads and writes in the same handler, you’re forcing synchronous reflow. Break it up:
// Bad: read, write, read, write in one handler
button.addEventListener('click', () => {
const height = panel.offsetHeight; // read
panel.style.height = height + 10 + 'px'; // write
const width = panel.offsetWidth; // read (forces reflow)
panel.style.width = width + 10 + 'px'; // write
});
// Better: batch reads, then writes, then yield
button.addEventListener('click', async () => {
const height = panel.offsetHeight;
const width = panel.offsetWidth;
await new Promise(r => requestAnimationFrame(r));
panel.style.height = height + 10 + 'px';
panel.style.width = width + 10 + 'px';
});
For heavier work, use scheduler.yield() where supported, or fall back to setTimeout(fn, 0). It lets the browser paint between chunks of work instead of holding the main thread hostage.
2. Stop shipping JavaScript you don’t use
Third-party scripts are the number one cause of bad INP and LCP on small business sites. Chat widgets, heatmap tools, and that one analytics tag from 2019 that nobody remembers installing. Open DevTools, go to the Coverage tab, and look at what’s actually executing. I’ve seen sites cut 400KB of unused JS and watch INP drop by half.
If a script only matters after interaction, load it on interaction:
<script>
const loadChat = () => {
const s = document.createElement('script');
s.src = 'https://example.com/chat-widget.js';
document.head.appendChild(s);
};
window.addEventListener('scroll', loadChat, { once: true, passive: true });
window.addEventListener('pointerdown', loadChat, { once: true, passive: true });
</script>
That single pattern fixes more INP problems than any plugin will.
3. Serve images in the right format and the right size
LCP is usually an image. In 2026 there’s no excuse for shipping a 2MB hero JPEG. Use AVIF with a WebP fallback, and let the browser pick:
<picture>
<source srcset="hero.avif" type="image/avif">
<source srcset="https://i0.wp.com/www.kennykey.com/hero.webp" type="image/webp">
<img src="hero.jpg" width="1200" height="630"
alt="Hero" fetchpriority="high" decoding="async">
</picture>
The fetchpriority="high" on your LCP image is a real win and easy to miss. And always set explicit width and height so the browser reserves space and your CLS stays at zero.
4. Preconnect to the domains you actually depend on
Fonts, CDNs, and analytics all cost a DNS lookup plus a TLS handshake on first load. If you know the domains up front, tell the browser early:
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="https://www.googletagmanager.com">
Don’t go crazy. Two or three preconnects max. Every one you add competes for bandwidth with the resources that actually matter.
5. Self-host your fonts and subset them
Google Fonts is fine, but the request chain from a third-party domain slows down text rendering and can cause layout shift when the font swaps in. Self-host, subset to the characters you use, and use font-display: swap:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-subset.woff2') format('woff2');
font-weight: 400 700;
font-display: swap;
unicode-range: U+0000-00FF;
}
The unicode-range line is the one people skip. It tells the browser to only download the font when a matching character appears, which cuts a lot of wasted bytes on pages that are mostly English.
6. Kill layout shift from ads, embeds, and cookie banners
CLS is almost always something that loads after the page and pushes content around. The fix is to reserve space before it loads. For a cookie banner or a late-loading ad slot:
.ad-slot {
min-height: 250px;
contain: layout;
}
For iframes, set aspect-ratio on the container so the box is the right size from the first paint. If you can’t predict the height, add a placeholder skeleton with the same dimensions. Users won’t notice. Google will.
7. Measure from the field, not just Lighthouse
Lighthouse is a lab test on a fast connection. It’s useful for catching obvious problems, but your real score comes from the Chrome User Experience Report, which is field data from actual users. If you want to see what your visitors actually experience, wire up the web-vitals library:
import { onLCP, onINP, onCLS } from 'web-vitals';
const report = (metric) => {
navigator.sendBeacon('/analytics', JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
rating: metric.rating
}));
};
onLCP(report);
onINP(report);
onCLS(report);
That gives you real numbers from real devices, including the cheap Android phone on a slow connection that Lighthouse never simulates properly. If you’re running a business site and don’t want to babysit this, it’s the kind of thing that falls under ongoing Long Island web design work, not a one-time cleanup.
What to do first
If you only have an afternoon, do this in order:
- Check field data in PageSpeed Insights and find your worst metric.
- If INP is the problem, audit third-party scripts and long tasks.
- If LCP is the problem, find the LCP element and fix its loading.
- If CLS is the problem, reserve space for anything that loads late.
Don’t chase a perfect 100. Google uses the 75th percentile, and a good score across real users beats a perfect Lighthouse number every time. If you want the technical work done alongside your Long Island SEO strategy, it makes sense to treat performance as part of the whole picture rather than a separate project you’ll get to “someday.”
FAQ
Do Core Web Vitals still affect rankings in 2026?
Yes, but they’re a tiebreaker, not a primary signal. Content relevance and links matter more. That said, a slow site hurts engagement, and engagement feeds rankings indirectly.
Is FID still a thing?
No. Google retired First Input Delay in March 2024 and replaced it with Interaction to Next Paint. If you’re reading a guide that still talks about FID, close the tab.
How long until I see changes after fixing something?
Field data in the CrUX report updates roughly every 28 days, so plan for about a month before Google’s numbers reflect your fixes. Lab tools like Lighthouse will show improvements immediately.


