Skip to content

Web Development · Performance

AVIF vs WebP: Web Image Optimization for LCP 2026

AVIF and WebP now have near-universal browser support. Here's the image optimization stack that actually improves LCP scores in production in 2026.

Anurag Verma

Anurag Verma

7 min read

Web Images in 2026: AVIF, WebP, and the LCP Work Nobody Does Until It's a Problem

Sponsored

Share

Check your site’s LCP on a mobile connection and there’s a reasonable chance an image is the culprit. Not JavaScript. Not fonts. An unoptimized JPEG or PNG that nobody revisited after it was uploaded two years ago.

Image optimization isn’t technically hard. The formats have been stable for years, the tooling is good, and browser support has caught up. What gets in the way is that it’s easy to deprioritize, because images work. They’re just slow, and slow doesn’t fail visibly the way a broken API call does. LCP scores sit in the yellow until someone decides to fix them.

This is the setup worth putting in place, and it’s not that much work. Images are only one piece of frontend performance; if animation jank is also part of your LCP or INP story, our GSAP vs Framer Motion vs CSS breakdown covers what’s cheap to animate and what isn’t.

Where Browser Support Actually Stands in 2026

WebP has been supported everywhere since 2020. Safari added support in version 14. There is no meaningful browser population that doesn’t support WebP. If you’re still serving JPEG by default, you’re leaving compression on the table for every user.

AVIF (AV1 Image File Format) has supported in Chrome since 2020, Firefox since 2021, and Safari since version 16 (2022). Global browser support is above 90%. The holdout was Safari, and it’s been more than three years since that changed.

AVIF produces smaller files than WebP at the same visual quality, especially for photos with complex detail. The encoding is slower (AVIF encoding can take 10-20x longer than WebP encoding), but this is a build-time concern, not a serving concern. For CDN-delivered content, you encode once and serve many times.

Format Comparison for Common Image Types

Image typeRecommended formatNotes
Photos, hero imagesAVIF, fallback WebPBest compression ratios
Product imagesAVIF, fallback WebPAlso handles transparency
UI icons, logosSVG (preferred), WebPVector is usually better
Screenshots, diagramsWebP or PNGPNG for exact pixel accuracy
Animated imagesWebP or AVIFBoth support animation; prefer over GIF
Open Graph / socialJPEG or WebPSome crawlers still prefer JPEG

Serving Multiple Formats with <picture>

The browser picks the first source it supports:

<picture>
  <source srcset="/images/hero.avif" type="image/avif" />
  <source srcset="/images/hero.webp" type="image/webp" />
  <img
    src="/images/hero.jpg"
    alt="Team working at a conference table"
    width="1200"
    height="630"
    loading="lazy"
    decoding="async"
  />
</picture>

AVIF is listed first (modern browsers take it), WebP as the next choice, JPEG as the final fallback for very old clients. The <img> tag at the bottom is required: it’s the fallback and carries the alt, width, height, loading, and decoding attributes.

Responsive Images with srcset

Serving a 2400px image to a 375px phone is another common waste. srcset lets the browser pick the appropriate size:

<picture>
  <source
    type="image/avif"
    srcset="
      /images/hero-480.avif   480w,
      /images/hero-768.avif   768w,
      /images/hero-1200.avif 1200w,
      /images/hero-2400.avif 2400w
    "
    sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1200px"
  />
  <source
    type="image/webp"
    srcset="
      /images/hero-480.webp   480w,
      /images/hero-768.webp   768w,
      /images/hero-1200.webp 1200w,
      /images/hero-2400.webp 2400w
    "
    sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1200px"
  />
  <img
    src="/images/hero-1200.jpg"
    alt="Team working at a conference table"
    width="1200"
    height="630"
  />
</picture>

The sizes attribute tells the browser how wide the image will be rendered at different viewport widths. Combined with srcset, the browser multiplies the display size by the device pixel ratio and fetches the closest match. A 375px device at 3x DPR fetches the 1200px variant, not the 2400px one.

Generating Multiple Formats at Build Time

With Sharp (Node.js)

Sharp is the standard Node image processing library. Fast, minimal dependencies, good output quality.

import sharp from "sharp";
import { readdir, mkdir } from "fs/promises";
import path from "path";

const INPUT_DIR = "public/images/source";
const OUTPUT_DIR = "public/images/optimized";

const WIDTHS = [480, 768, 1200, 2400];
const QUALITY = { avif: 60, webp: 80, jpg: 85 };

async function processImage(inputPath: string, baseName: string) {
  const img = sharp(inputPath);
  const { width: originalWidth } = await img.metadata();

  for (const width of WIDTHS) {
    if (originalWidth && width > originalWidth) continue;

    const base = `${baseName}-${width}`;

    await img.clone().resize(width).avif({ quality: QUALITY.avif }).toFile(
      path.join(OUTPUT_DIR, `${base}.avif`)
    );

    await img.clone().resize(width).webp({ quality: QUALITY.webp }).toFile(
      path.join(OUTPUT_DIR, `${base}.webp`)
    );

    await img.clone().resize(width).jpeg({ quality: QUALITY.jpg, mozjpeg: true }).toFile(
      path.join(OUTPUT_DIR, `${base}.jpg`)
    );
  }
}

Run this as a build step. For content sites with many images, add incremental processing: track which source files have changed and only reprocess those.

With Squoosh CLI

Squoosh’s CLI is useful for batch encoding when you want to tune quality settings interactively first:

npx @squoosh/cli --avif '{"quality": 60}' --webp '{"quality": 80}' -d output/ images/*.jpg

Framework-Level Optimization

If you’re using Next.js, the next/image component handles format selection, responsive srcsets, and lazy loading automatically. It converts to WebP or AVIF on demand and caches the results.

import Image from "next/image";

export function HeroImage() {
  return (
    <Image
      src="/images/hero.jpg"
      alt="Team working at a conference table"
      width={1200}
      height={630}
      priority  // removes lazy loading for LCP images
      quality={80}
    />
  );
}

For Astro, the <Image> component does the same. For other frameworks, check whether there’s a built-in image component before hand-rolling your own pipeline.

The LCP Image Specifically

For the page’s LCP element (usually the largest above-the-fold image), loading="lazy" is the wrong choice. Lazy loading defers the fetch until the image is near the viewport, which means the LCP image fetch starts late.

For the LCP image:

  • Remove loading="lazy" or use loading="eager"
  • Add fetchpriority="high" to tell the browser to prioritize this fetch
  • Add a <link rel="preload"> in the <head> so the browser discovers it early
<head>
  <link
    rel="preload"
    as="image"
    href="/images/hero-1200.avif"
    imagesrcset="/images/hero-480.avif 480w, /images/hero-1200.avif 1200w"
    imagesizes="(max-width: 480px) 480px, 1200px"
    type="image/avif"
  />
</head>

<body>
  <picture>
    <source
      type="image/avif"
      srcset="/images/hero-480.avif 480w, /images/hero-1200.avif 1200w"
      sizes="(max-width: 480px) 480px, 1200px"
    />
    <img
      src="/images/hero-1200.jpg"
      alt="Team working"
      width="1200"
      height="630"
      fetchpriority="high"
    />
  </picture>
</body>

The preload hint ensures the browser starts fetching the AVIF version before it processes the full HTML. For pages where the LCP image is on the critical path, this alone can meaningfully improve measured LCP.

CDN Delivery

If you’re serving images via a CDN, you can often offload format conversion entirely. Cloudflare Images, Cloudinary, Imgix, and similar services accept a source image URL and return the right format based on the Accept header. The transport layer matters here too; our explainer on HTTP/3 and QUIC covers how the underlying protocol affects how fast those CDN-delivered assets actually arrive.

# Cloudinary example: request an image with automatic format selection
https://res.cloudinary.com/demo/image/upload/f_auto,q_auto/sample.jpg

f_auto lets Cloudinary choose AVIF, WebP, or JPEG based on browser support. q_auto adjusts quality based on perceived visual difference. The original source file never changes; the CDN handles serving the right format to each client.

This is the lowest-friction path for sites with user-uploaded content or large existing image catalogs. You don’t need to regenerate files. Just change the delivery URL.

Checking Your Work

After making changes, check your LCP images with:

  • Chrome DevTools Network tab: Look at the image requests. Are they fetching AVIF/WebP? Check the size compared to the original.
  • PageSpeed Insights / Lighthouse: The “Serve images in next-gen formats” and “Properly size images” audits tell you which images still need work.
  • Core Web Vitals report in Search Console: Shows LCP field data from real users, which is what Google actually uses for ranking.

The goal isn’t a perfect Lighthouse score on your dev machine. It’s a good LCP on a real device on a real connection. Run Lighthouse in “mobile” mode with CPU throttling enabled to see what actual users on mid-tier phones experience. LCP is only one of the Core Web Vitals; if interactivity is also slow on your site, see our Interaction to Next Paint guide for the responsiveness side of the equation.

Frequently asked questions

Should I use AVIF or WebP for images in 2026?
Use AVIF as your first choice since it produces smaller files than WebP at the same visual quality, especially for complex photos, and has over 90% global browser support. Serve WebP as the fallback and JPEG as the final fallback for very old clients, all inside a single `<picture>` element.
Why shouldn't the LCP image use loading="lazy"?
Lazy loading defers the image fetch until it's near the viewport, which delays the exact fetch that determines your Largest Contentful Paint score. For the LCP image, remove lazy loading, add `fetchpriority="high"`, and preload it in the `<head>` so the browser starts fetching it immediately.
How do I generate AVIF and WebP versions of my images automatically?
Use Sharp in a Node.js build script to generate multiple widths and formats at build time, or use the Squoosh CLI for interactive quality tuning. If you're on Next.js or Astro, the built-in Image components handle format selection and responsive sizing automatically.
Do I need to manually convert images if I use a CDN?
No. Services like Cloudinary and Cloudflare Images can convert format and quality on the fly based on the browser's `Accept` header, so you keep your original source files and just change the delivery URL. This is the lowest-friction option for sites with large existing image catalogs.

Sponsored

Sponsored

Discussion

Join the conversation.

Comments are powered by GitHub Discussions. Sign in with your GitHub account to leave a comment.

Sponsored