Skip to content
yutils

Image Optimization for the Web — WebP, AVIF, srcset, and the Right Compression

Modern image formats compared, when to pick JPEG vs WebP vs AVIF, responsive images with srcset, lazy loading, and how compression actually works.

~8 min read

The heaviest element on most web pages is almost always an image. A well-optimised site hits 1.5 s LCP (Largest Contentful Paint); a neglected one sits at 5 s+. This guide covers which format to use in 2026, how to deliver the right size with srcset, and the truth about lazy loading and priority hints.

Formats — JPEG, PNG, WebP, AVIF

FormatStrengthWeaknessSupport (2026)
JPEGUniversal, great photo compressionNo transparency, 20–50% larger than WebP/AVIF100%
PNGLossless, transparency, simple graphicsBloated for photos100%
WebP25–35% smaller than JPEG, transparencyMisses some legacy environments97%+ (Safari 14+)
AVIF50% smaller than JPEG, HDRSlow encoding93%+ (Safari 16+)
SVGVector, scales infinitelyNot for raster photos100%

2026 recommendations:

  • Logos and icons: SVG.
  • Photos (blog, hero): AVIF with WebP and JPEG fallbacks.
  • UI illustrations, transparent graphics: WebP or PNG.

Quality vs file size

The quality slider in JPEG/WebP/AVIF is not a percentage — 80 means different things in each format. Good defaults:

  • JPEG quality 80 — visually indistinguishable; you can drop to 50 on mobile and most users won't notice.
  • WebP quality 75–80 — matches JPEG 80.
  • AVIF quality 50–60 — matches JPEG 80, with much smaller files.

Different sites have different sweet spots. Image Resize & Compress has a quality slider and a compression-ratio readout to find your threshold quickly.

Resolution — match the device

The biggest waste: sending a 1920 px image to a 360 px mobile. Even with retina (2×), 720 px is enough; the rest is traffic you'll never see.

Provide candidates via srcset and let the browser pick:

<img
  src="hero-1280.jpg"
  srcset="hero-640.jpg 640w, hero-1280.jpg 1280w, hero-1920.jpg 1920w"
  sizes="(max-width: 768px) 100vw, 50vw"
  alt="..."
  loading="lazy"
  width="1280"
  height="720"
/>
  • srcset — candidates + width descriptor (w).
  • sizes — how wide the image will render. The browser uses this to pick from srcset.
  • width and height attributes — establish aspect ratio → no CLS. (CSS can still resize while preserving ratio.)

Multiple formats with picture

Prefer AVIF/WebP, fall back to JPEG.

<picture>
  <source type="image/avif" srcset="hero.avif" />
  <source type="image/webp" srcset="hero.webp" />
  <img src="hero.jpg" alt="..." loading="lazy" />
</picture>

The browser picks the first source it can handle. If none, the final img. srcset works inside source too.

Lazy loading

Images outside the viewport don't need to load up front.

<img src="..." loading="lazy" alt="..." />

Chrome 76+, Firefox 75+, Safari 15.4+. For the LCP candidate (the big hero image), use eager + high priority:

<img
  src="hero.jpg"
  loading="eager"
  fetchpriority="high"
  alt="..."
/>

fetchpriority was standardized in 2024. It tells the browser which image is the LCP candidate among several.

Inline base64 vs external file

Small icons (under ~1 KB) can be inlined as base64 data URIs to save an HTTP request. Caveats:

  • Base64 is ~33% larger than raw — inlining big images backfires.
  • Not cached. The same image on multiple pages is downloaded each time.
  • Most common as background-image: url(data:...) in CSS.

Drop an image into Image to Base64 (Data URI) for an instant data URI; decide based on the resulting size.

SVG optimization

  • Editor exports (Illustrator, Figma) include extra noise. Run through svgo or SVGOMG (browser) — 50–80% reductions are routine.
  • Keep viewBox; remove fixed width/height so CSS can resize freely.
  • XSS risk — sanitize user-provided SVG with DOMPurify before inlining. External <img> is safe.

CDN + dynamic resize

Cloudflare Images, imgix, and Cloudinary expose URL parameters for on-the-fly resize, format conversion, and quality control — img.example.com/hero.jpg?w=640&fm=avif style.

  • Pro: one source → device-specific optimization automatically.
  • Con: costs money. Small sites do fine with build-time static resize.

Static-site frameworks (Next.js, Astro, Hugo) resize at build time; next/image auto-generates srcset and picture.

Common pitfalls

1. Serving the original

A 4000-px RAW dropped straight into <img>. CSS sizes it to 200 px but the user still downloads 4000 px. Resize at build or via CDN.

2. Missing width/height

Without the ratio, the browser shifts layout when the image loads → CLS penalty in Core Web Vitals. Set the attributes or use CSS aspect-ratio.

3. PNG for photos

PNG is for graphics and icons. Photos in PNG are 3× the size of an equivalent JPEG/WebP/AVIF for the same visual quality.

4. Lazy-loading everything

Marking the first-viewport image loading="lazy" delays LCP. Above-the-fold images need eager + high priority.

5. Using CSS background for content images

<img alt> beats CSS background for SEO and accessibility. Reserve background-image for decoration.

6. Empty or "image" alt

alt is read by screen readers, indexed by search engines, and shown when the image fails. Write meaningful text. For pure decoration, use alt="" explicitly.

Core Web Vitals impact

  • LCP — the hero image is usually the LCP element. AVIF + priority + proper size keeps LCP under 2.5 s.
  • CLS — prevent with width/height attributes.
  • INP — image decoding can block the main thread. decoding="async" moves it off-thread.

Summary

  • Format priority: AVIF > WebP > JPEG for photos; SVG for logos and icons; PNG for transparent graphics.
  • <picture> + srcset + sizes deliver the right image per device.
  • Always include width and height — no CLS.
  • LCP candidate = eager + fetchpriority high. Everything else = lazy.
  • Tiny icons inline as base64. Larger images stay external and cache.
  • Quick quality tuning lives in Image Resize & Compress with a slider and compression readout.
Back to guides