Image Optimization for Core Web Vitals: A Developer's Guide
Practical techniques to optimize images for LCP, CLS, and INP. Covers formats, responsive images, lazy loading, preloading, and CDN automation.
Your Core Web Vitals are failing. And images are almost certainly the reason.
Images make up the single largest chunk of page weight on most websites. They’re the number one cause of slow LCP, the most common trigger for layout shift, and the easiest performance problem to fix once you know what to do.
This guide covers the practical techniques that actually move the needle.
What Are Core Web Vitals?
Core Web Vitals are three metrics Google uses to measure real-world user experience. They directly affect your search rankings.
- Largest Contentful Paint (LCP): How fast does the biggest visible element load? Target: under 2.5 seconds. The LCP element is usually a hero image or banner.
- Cumulative Layout Shift (CLS): How much does the page jump around while loading? Target: under 0.1. Images without explicit dimensions are one of the top causes.
- Interaction to Next Paint (INP): How snappy does the page feel when users click or tap? Target: under 200ms. Heavy image processing on the main thread can block interactions.
Images affect all three, but LCP and CLS are where the big wins live.
Fixing LCP: Make Your Hero Image Load Fast
The hero image is often the LCP element. Every millisecond you shave off its load time directly improves your score. Here’s how to approach it.
Preload the Hero Image
Browsers discover images only after parsing your CSS and HTML. That’s too late. Preloading tells the browser to start fetching immediately:
<head>
<link rel="preload" as="image" href="/images/hero.webp"
imagesrcset="/images/hero-400.webp 400w,
/images/hero-800.webp 800w,
/images/hero-1200.webp 1200w"
imagesizes="100vw">
</head>
This is one of the highest-impact changes you can make for LCP. It moves your hero image to the front of the browser’s fetch queue.
Use Modern Formats
JPEG is everywhere. It’s also no longer the best option. WebP delivers 25-35% smaller files at the same quality. AVIF pushes that to up to 50%. Both work in all major browsers now.
Use the <picture> element to serve the best format each browser supports:
<picture>
<source srcset="/images/hero.avif" type="image/avif">
<source srcset="/images/hero.webp" type="image/webp">
<img src="/images/hero.jpg" alt="Product showcase" width="1200" height="600">
</picture>
The browser picks the first source it supports and falls back to JPEG for the rare legacy case.
Serve Responsive Images
A 2400px image displayed on a 375px phone is a massive waste of bandwidth. It kills your LCP. Use srcset and sizes to let the browser choose the right resolution:
<img src="/images/hero-800.webp"
srcset="/images/hero-400.webp 400w,
/images/hero-800.webp 800w,
/images/hero-1200.webp 1200w,
/images/hero-1600.webp 1600w"
sizes="(max-width: 768px) 100vw, 50vw"
alt="Product showcase"
width="1600"
height="800">
The sizes attribute tells the browser how wide the image will actually display at each breakpoint. The browser then picks the smallest file that covers that width at the device’s pixel density.
Set fetchpriority on the LCP Image
The fetchpriority attribute tells the browser to prioritize this image over other resources:
<img src="/images/hero.webp" alt="Hero" width="1200" height="600"
fetchpriority="high">
Combine this with preloading for maximum LCP impact.
Fixing CLS: Stop the Layout Jumping
Ever had a page load and then everything jumps around as images pop in? That’s layout shift. It happens when the browser doesn’t know image dimensions before loading. The page renders with the image at zero height, then the whole layout lurches when the image arrives.
Always Set Width and Height
Simplest fix in this entire guide. Put width and height on every <img> tag:
<img src="/images/product.webp" alt="Product" width="800" height="600">
Modern browsers use these attributes to calculate the aspect ratio and reserve the correct space before the image loads. This works even with responsive CSS like max-width: 100%; height: auto;.
Use CSS aspect-ratio as a Fallback
For cases where you’re setting dimensions dynamically or using background images, the aspect-ratio property does the same job:
.hero-image {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}
The container holds its shape during loading. Zero layout shift.
Keep Above-the-Fold Images in the Initial HTML
If JavaScript injects an image into the visible area after initial render, it causes layout shift no matter what dimension attributes you set. Keep above-the-fold images in your server-rendered HTML.
Image Compression: Finding the Sweet Spot
Compression is a balancing act between file size and visual quality. Here are the numbers that work:
- JPEG: Quality 75-85 is the sweet spot for photographs. Below 70, artifacts get noticeable on close inspection.
- WebP: Quality 75-80 looks visually identical to JPEG 85, at much smaller file sizes.
- AVIF: Quality 60-70 matches JPEG 85 at roughly half the file size. Encoding is slower though, so pre-generate AVIF files rather than encoding on the fly.
- PNG: Only use for transparency or sharp text/line art. For photos, always go with JPEG/WebP/AVIF.
Run every image through an optimizer. Tools like Sharp (Node.js), Squoosh, or ImageOptim can automate this in your build pipeline.
Lazy Load Everything Below the Fold
Images that aren’t visible on the initial screen shouldn’t block the page. Native lazy loading works in all modern browsers:
<img src="/images/product-2.webp" alt="Product detail"
width="600" height="400"
loading="lazy">
Never lazy-load the LCP image. The hero image and anything visible in the initial viewport should load eagerly. Only slap loading="lazy" on images further down the page.
For long product listing pages, this one attribute can cut initial page weight by 60% or more.
Using an Image CDN to Automate the Whole Stack
Every technique above works great on its own. Together, they deliver excellent performance. But maintaining all of this manually (generating multiple formats, creating responsive size variants, compressing at the right quality, serving from edge locations) gets old fast.
An image CDN automates the entire pipeline. You upload your original high-resolution images once, and the CDN handles format conversion, resizing, compression, and global delivery on the fly.
Sirv does exactly this. When a visitor requests an image, Sirv automatically:
- Detects the browser and serves AVIF, WebP, or the best fallback format
- Resizes based on URL parameters, so you get any dimension without pre-generating variants
- Compresses with quality settings tuned per format
- Delivers from edge servers worldwide for minimal latency
A responsive image setup with Sirv looks like this:
<img src="https://demo.sirv.com/product.jpg?w=800"
srcset="https://demo.sirv.com/product.jpg?w=400 400w,
https://demo.sirv.com/product.jpg?w=800 800w,
https://demo.sirv.com/product.jpg?w=1200 1200w,
https://demo.sirv.com/product.jpg?w=1600 1600w"
sizes="(max-width: 768px) 100vw, 50vw"
alt="Product"
width="1600"
height="800">
You store one master image. Sirv generates every variant on demand and caches it at the edge. Format negotiation happens automatically through content negotiation. No <picture> element needed unless you want explicit control.
Quick Reference Checklist
Pin this somewhere. It works for any page:
- Identify the LCP element. If it’s an image, preload it and set
fetchpriority="high". - Add
widthandheightto every<img>tag. - Serve WebP or AVIF as the primary format. Use
<picture>or content negotiation. - Use
srcsetandsizesfor responsive delivery. - Apply
loading="lazy"to every image below the fold. - Compress to quality 75-80 for WebP, 60-70 for AVIF.
- Use an image CDN to automate format conversion, resizing, and global delivery.
What to Do Next
Start with the three changes that give you the biggest bang: preload your LCP image, add dimensions to prevent CLS, and switch to modern formats. You can do all three in an afternoon.
Then, when you’re tired of maintaining the optimization pipeline by hand, offload it to an image CDN like Sirv. Your images stay optimized as your catalog grows, without you touching a thing.
Faster pages. Better rankings. Happy users.