Core Web Vitals are the three metrics Google uses to measure real-world user experience on your website. They are direct ranking factors in search results — and images are the #1 cause of poor scores.
🎯 The Three Metrics — Overview
┌───────────────────────────────────────────────────────────────┐
│ Core Web Vitals │
│ │
│ LCP CLS INP │
│ ───────────────── ─────────────────── ────────────── │
│ Largest Cumulative Interaction │
│ Contentful Layout Shift to Next Paint │
│ Paint │
│ │
│ Load speed of Visual stability Responsiveness │
│ the largest element No content jumping to user input │
└───────────────────────────────────────────────────────────────┘
📊 Scoring Thresholds — Good / Needs Improvement / Poor
| Metric | Good ✅ | Needs Improvement ⚠️ | Poor ❌ |
|---|---|---|---|
| LCP | ≤ 2.5 seconds | 2.5 – 4.0 seconds | > 4.0 seconds |
| CLS | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |
| INP | ≤ 200ms | 200 – 500ms | > 500ms |
🖼️ 1 — LCP: Largest Contentful Paint
The reality: Images are the LCP element on 85% of desktop pages and 76% of mobile pages.
What makes up your LCP time:
TTFB (Time to First Byte)
├── DNS Lookup
├── TCP Connection
└── Server Response Time
Resource Load Delay
└── When does the browser discover the image?
Resource Download Time
└── File size ÷ network speed
Render Delay
└── Is the main thread busy?
──────────────────────────────────────────
= Total LCP time
✅ Top 5 LCP Fixes
1. Preload your hero image:
<link
rel="preload"
as="image"
href="hero.webp"
type="image/webp"
fetchpriority="high"
/>
2. Add fetchpriority directly to the image:
<img
src="hero.webp"
fetchpriority="high"
loading="eager"
alt="Page hero"
width="1200"
height="630"
/>
3. Convert to WebP or AVIF:
JPEG Hero (200 KB) → WebP Hero (120 KB) → LCP improves by 0.5–1.5 seconds
4. Serve from a CDN:
Without CDN: User in London ← Server in California (180ms latency)
With CDN: User in London ← Nearby edge node (10–30ms latency) ✅
5. Never load images with JavaScript:
// ❌ Wrong — delays browser image discovery
const img = new Image();
img.src = 'hero.jpg';
document.body.appendChild(img);
// ✅ Correct — inline HTML is always faster
// <img src="hero.webp" fetchpriority="high" />
🏗️ 2 — CLS: Cumulative Layout Shift
Without width/height on the image:
┌─────────────────────────┐ ┌─────────────────────────┐
│ Page Headline │ │ │
│ │ → │ [Image loading... │
│ [content jumps down] │ │ Page Headline │
│ Text shifts here │ │ Text shifts here │
└─────────────────────────┘ └─────────────────────────┘
Before image loads After image loads
CLS = 0 (good) CLS = 0.25+ (poor ❌)
The fix:
<!-- ✅ Always declare width and height -->
<img src="product.webp" width="400" height="400" alt="Product" />
<!-- ✅ Or reserve space with CSS -->
.image-container {
aspect-ratio: 16 / 9;
width: 100%;
}
Common CLS Causes Related to Images
| Cause | Impact | Fix |
|---|---|---|
Missing width & height | High | Always declare them |
| Dynamic ad injection | High | Reserve space in advance |
| Web fonts loading late | Medium | font-display: swap |
| JS-injected content | High | Use layout placeholders |
| Embeds without dimensions | High | Set explicit dimensions |
🖱️ 3 — INP: Interaction to Next Paint
INP measures the time from a user’s click or tap to the moment the screen visually responds. Images affect INP when their decoding puts heavy pressure on the main thread.
Interaction lifecycle:
User clicks / taps
↓
Input Delay (waiting for main thread)
↓
Processing Time (executing code)
↓
Presentation Delay (rendering to screen)
─────────────────────────────────────────
= Total INP (must be < 200ms)
INP improvements related to images:
<!-- Async decoding offloads main thread pressure -->
<img src="hero.webp" decoding="async" />
<!-- Lazy load non-critical images -->
<img src="section.webp" loading="lazy" decoding="async" />
🔧 Tools to Measure Core Web Vitals
┌──────────────────────────────────────────────────────────────┐
│ PageSpeed Insights (pagespeed.web.dev) │
│ → Measures LCP, CLS, INP in seconds │
│ → Uses real Chrome User Experience Report data │
│ │
│ Google Search Console │
│ → Core Web Vitals report across all your pages │
│ → Alerts for pages that need improvement │
│ │
│ Chrome DevTools (F12) │
│ → Performance tab → find the LCP element │
│ → Network tab → inspect image file sizes │
│ │
│ Lighthouse (CLI or Chrome Extension) │
│ → Full audit with specific, actionable recommendations │
└──────────────────────────────────────────────────────────────┘
📊 How Images Impact All Three Metrics
| Metric | Image-Related Cause | Fix |
|---|---|---|
| LCP | Unoptimized hero image | Convert to WebP, preload, use CDN |
| LCP | Image discovered late | Inline <img>, not JS-loaded |
| CLS | No width/height on <img> | Always declare dimensions |
| CLS | Images injected by JS | Use layout placeholders |
| INP | Heavy image decoding | decoding="async" |
| INP | Too many images loading | loading="lazy" for off-screen |
✅ Full Core Web Vitals × Images Checklist
LCP
- [ ] Identify your LCP element in Chrome DevTools
- [ ] Convert it to WebP or AVIF
- [ ] Add
<link rel="preload">in<head> - [ ] Add
fetchpriority="high"on the image - [ ] Serve from a CDN
- [ ] Target file size < 120 KB
CLS
- [ ] Add
widthandheightto every<img> - [ ] Use
aspect-ratioin CSS for fluid images - [ ] Reserve space for ad slots before they load
- [ ] Test the page on a slow network (Chrome DevTools → Throttle)
INP
- [ ] Add
decoding="async"to large images - [ ] Avoid loading images via JavaScript
- [ ] Use
loading="lazy"for all below-the-fold images
📈 Expected Results After Optimization
Typical site — before and after image optimization:
LCP: 4.2s → 2.3s ✅ (+45% faster)
CLS: 0.28 → 0.04 ✅ (86% improvement)
INP: 380ms → 180ms ✅ (53% improvement)
PageSpeed score: 54 → 87 📈
Google ranking: Significant improvement 📈
Bounce rate: Drops measurably 📉
Conversion rate: Increases 📈
🔗 Related Articles:
- PageSpeed Tips ← Push your score above 90
- Compression Guide ← Reduce image file sizes
