Image Optimization: Formats, Compression, and Lazy Loading Done Right
- Filed November 10, 2026
- Page speed and Core Web Vitals, guide 4 of 10
Images can be the largest files on a page, and an image can be the page’s Largest Contentful Paint element. Optimizing them is a delivery problem with five levers: format, compression, dimensions, loading priority and caching. Each lever has a failure mode. Lazy loading is the clearest example: it saves bandwidth for images further down the page and slows LCP when applied to the hero image. Each lever below therefore comes with the check that shows whether it helped.
Format
| Format | Use for | Notes |
|---|---|---|
| AVIF | Photographs and complex images where supported | High compression efficiency; encode time can be longer |
| WebP | Photographs and graphics | Broad browser support |
| JPEG | Photographs, fallback | Universal support |
| PNG | Graphics needing lossless quality or transparency | Large for photographs |
| SVG | Icons, logos, simple illustrations | Vector; scales without loss |
Serve modern formats with a fallback using the <picture> element, or let an image CDN negotiate the format from the browser’s Accept header. web.dev notes that with image CDNs the format requested and the format returned can differ, so check the response content-type rather than the file extension (image CDNs).
Compression
Pick a quality setting per image type and check visually at the size the image is displayed; there is no universal number. Strip unnecessary metadata, but keep copyright or licensing information if you rely on it.
web.dev reports that switching to an image CDN can save 40 to 80 percent of image file size. That range is web.dev’s estimate for image CDN adoption, not a guarantee for any particular site; measure your own before and after.
Dimensions and responsive images
Serving a 2,400-pixel image into a 600-pixel slot wastes bytes. Use srcset and sizes so the browser picks an appropriate file:
<img src="/img/sofa-800.webp"
srcset="/img/sofa-400.webp 400w, /img/sofa-800.webp 800w, /img/sofa-1600.webp 1600w"
sizes="(max-width: 600px) 100vw, 50vw"
width="800" height="600"
alt="Three-seat sofa in green velvet with oak legs">
Always include width and height attributes (or an equivalent CSS aspect-ratio). web.dev’s CLS guide lists images without dimensions among the most common causes of poor Cumulative Layout Shift and recommends always including size attributes (optimizing CLS).
Loading priority and lazy loading
Lazy loading defers off-screen images until the user scrolls near them. web.dev’s guidance says: “Use loading=lazy only for images outside the initial viewport”, and “especially for LCP images, use the browser’s default eager loading” (browser-level lazy loading). It adds that an image with both loading="lazy" and fetchpriority="high" is still delayed while off-screen.
web.dev’s analysis of HTTP Archive data found that the median page without lazy loading had a 75th percentile LCP of 2,922 milliseconds, against 3,546 milliseconds for the median page with lazy loading (lazy loading and LCP). That is a correlation across the web, not a measured effect on any one site; web.dev’s own reading is that sites using lazy loading tend to have worse LCP, which is consistent with lazy loading being applied to images in the initial viewport.
Priority: for the LCP image, add fetchpriority="high"; web.dev describes this as a way to make LCP happen sooner (fetch priority).
Lazy loading and Google: Google’s lazy-loading guidance for Search says implementations must load relevant content when it is visible in the viewport, because “Google Search does not interact with your page”, and recommends not lazy-loading content likely to be visible when the page opens (Google on lazy-loading). Native loading="lazy" and IntersectionObserver-based loaders meet this; loaders that wait for scroll events or clicks may not.
Caching
Set long cache lifetimes for versioned image URLs (for example, file names containing a hash) and change the URL when the image changes. This avoids repeated downloads on repeat visits without serving stale images.
Before and after configuration
Before (illustrative): a product page loads eight 2,000-pixel JPEGs at full quality, all with loading="lazy", including the main product photo at the top. No width or height attributes.
After:
- the main product photo is served as AVIF or WebP at three sizes via
srcset, eager-loaded withfetchpriority="high"; - the seven gallery thumbnails below the fold are lazy-loaded at thumbnail size;
- every image has width and height;
- images are served from a CDN with long-lived cache headers and hashed file names.
Expected result: fewer bytes, earlier LCP, no layout shift from images.
Verification: in DevTools’ Network panel, compare total image bytes and the LCP image’s start time; in PageSpeed Insights, compare lab LCP and CLS; in the field, check the Core Web Vitals report after the 28-day data window has refreshed.
Failure conditions: a CDN that serves an unsupported format to an older browser; sizes values that do not match the layout, causing oversized downloads; lazy loading re-applied to the main image by a theme update.
Images and search visibility
Performance and discoverability are separate topics. Delivery work makes images load faster; whether they appear in Google Images or Lens depends on alt text, page context and indexability. Two places where the topics meet:
- Google’s lazy-loading guidance means a lazy-loading method that hides images from Google also hides them from image search.
- Responsive image markup and
srcsetdo not prevent indexing; Google’s image documentation covers how it discovers images in<img>elements (Google’s image SEO best practices).
Image delivery checklist
- [ ] Modern formats with fallbacks; response
content-typechecked. - [ ] Compression chosen per image type and checked visually.
- [ ]
srcsetandsizesmatch the layout. - [ ] Width and height on every image.
- [ ] LCP image eager-loaded with
fetchpriority="high". - [ ] Only below-the-fold images lazy-loaded, using native lazy loading or an IntersectionObserver-based loader.
- [ ] Long cache lifetimes with versioned URLs.
- [ ] Results checked in lab and field data.