In Part 1 of this series, I covered what Core Web Vitals are, the 2026 thresholds, what’s changed in the ecosystem, and how to measure them accurately. If you need a refresher on LCP, INP, CLS, or the lab-vs-field gap, start there.
This part is all action. Whether you’ve got 30 minutes to fix red metrics or want a comprehensive optimization strategy, everything here is battle-tested.
tipThis is the fast triage article in the 2026 series. If these quick wins do not move the real problem, go next to the troubleshooting guide. If you need the ongoing guardrails, jump to Lighthouse CI and RUM automation.
Quick Wins: Passing Core Web Vitals in 30 Minutes
Alright. Red Core Web Vitals? Got 30 minutes?
Here’s the fastest path to green. These hit the 80% of cases that have obvious culprits. If your problem is weird (and sometimes they are), you’ll need to dig deeper.
For LCP
- Add
fetchpriority="high"andloading="eager"to your hero image. The browser needs to know this is the most important image on the page.
<img
src="hero.webp"
alt="Article hero image"
width="1200"
height="630"
fetchpriority="high"
loading="eager"
/>- Preload your hero image. Add a
<link rel="preload">in the<head>so the browser starts downloading it before it encounters the<img>tag:
<link rel="preload" as="image" href="/hero.webp" />Inline critical CSS or preload your main stylesheet. If your CSS is render-blocking, LCP can’t complete until it’s downloaded and parsed.
Move render-blocking scripts to
deferorasync. Any<script>tag in the<head>withoutdeferorasyncblocks rendering:
<!-- Before: blocks rendering -->
<script src="/analytics.js"></script>
<!-- After: doesn't block rendering -->
<script src="/analytics.js" defer></script>- Check whether the origin is consistently slow. If the HTML itself arrives late, frontend fixes alone may not be enough. That is your sign to review caching, redirects, origin work, or CDN setup.
For INP
Identify long tasks. Open Chrome DevTools → Performance panel, record a few interactions, and look for tasks longer than 50ms. Those are your targets.
Break up long tasks and yield between chunks where supported. This keeps the browser from staying blocked through one giant unit of work:
async function processLargeDataset(items) {
for (const item of items) {
processItem(item);
if (typeof scheduler !== 'undefined' && scheduler.yield) {
await scheduler.yield();
} else {
await new Promise(requestAnimationFrame);
}
}
}- Debounce or throttle event handlers. Scroll, resize, and input handlers that fire on every event are a classic INP killer:
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
window.addEventListener('scroll', debounce(handleScroll, 100));Use
requestIdleCallbackfor non-urgent work. If something doesn’t need to happen immediately (tracking, prefetching, analytics), push it to idle time.Lazy-load below-the-fold components. Don’t hydrate interactive components that aren’t visible yet. In frameworks like Astro, this happens naturally with islands architecture.
For CLS
- Set explicit
widthandheighton all<img>and<video>elements. This is the single biggest CLS fix. The browser reserves space before the image loads:
<img src="photo.webp" width="800" height="600" alt="..." />- Reserve space for ads, embeds, and dynamic content. Use
min-heighton containers that will be filled later:
.ad-container {
min-height: 250px;
}- Use
font-display: optionalorswapwith size-adjusted fallback fonts. Font loading is a sneaky CLS source.font-display: optionalprevents layout shifts entirely by using the fallback if the web font isn’t cached:
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: optional;
size-adjust: 102%;
}- Never insert content above existing content after initial render. Banners, cookie notices, and alert bars should push content down from the top before the main content paints, or overlay without shifting layout.
When Quick Wins Aren’t Enough
If the obvious fixes do not move the problem, the next question is not “what random optimization trick is next?” It is: what kind of bottleneck is this really?
- LCP is still slow because discovery is late or the origin is slow → go to the troubleshooting guide
- INP is still poor because the app does too much JavaScript work → go to Advanced Core Web Vitals
- You need guardrails so regressions stop shipping → go to Lighthouse CI and RUM automation
- The conversation has shifted to rankings and search impact → go to Core Web Vitals and SEO
This article is meant to buy you the first wins, not to replace the rest of the cluster.
The 30-Minute Checklist
If you only need the short version, do this:
- Confirm the failing metric in field data first
- Apply one or two obvious fixes, not ten speculative ones
- Re-test in lab tools to confirm the specific bottleneck moved
- Deploy and give field data time to catch up
- Escalate only after the obvious fixes stop working
That sounds almost too simple.
Most of the time, that is exactly why it works.
Related Reading
- Need the full mental model? Core Web Vitals guide
- Need a diagnostic workflow? CWV troubleshooting guide
- Need the SEO nuance? Core Web Vitals and SEO
- Need automation and monitoring? Automated Performance Testing with Lighthouse CI & GitHub Actions
- Need the deeper edge-case playbook? Advanced Core Web Vitals
- Need image-specific help? Image Optimization for the Modern Web
Summary
- The metrics are stable: LCP ≤ 2.5s, INP ≤ 200ms, CLS ≤ 0.1 at the 75th percentile
- Field data leads the prioritization
- Most first wins are still boring wins: earlier discovery, less blocking work, more stable layout
- Quick wins are step one, not the whole strategy
Get the easy improvements first. Then let the harder article do the harder job.
Happy shipping!
This article is part of the Core Web Vitals in 2026 series. For the deeper follow-up work, continue with the troubleshooting guide, the SEO nuance piece, the automation guide, and the advanced optimization article.





