Image Optimization

Images are typically the heaviest assets on a web page. According to the HTTP Archive, images account for roughly 50% of the total transfer size of the average web page. An unoptimized hero image can single-handedly push your Largest Contentful Paint (LCP) past the 2.5-second threshold. The good news is that image optimization offers some of the highest-impact performance wins available, often requiring minimal code changes.

Modern Image Formats

The choice of image format has a massive impact on file size. Older formats like JPEG and PNG are still widely used, but modern alternatives deliver the same visual quality at dramatically smaller file sizes.

WebP

WebP was developed by Google and is supported by all modern browsers (Chrome, Firefox, Safari, Edge). It offers significant compression advantages over both JPEG and PNG:

  • Lossy WebP produces files roughly 25-35% smaller than equivalent-quality JPEG images
  • Lossless WebP produces files roughly 25% smaller than PNG
  • Supports transparency (alpha channel), unlike JPEG
  • Supports animation, replacing animated GIFs at a fraction of the file size

AVIF

AVIF (AV1 Image File Format) is a newer format based on the AV1 video codec. It offers the best compression ratios currently available:

  • Roughly 50% smaller than JPEG at comparable visual quality
  • Roughly 20% smaller than WebP in many cases
  • Supports HDR (high dynamic range) and wide color gamut
  • Supports transparency and animation
  • Supported by Chrome, Firefox, and Safari (since version 16.4)

The tradeoff with AVIF is encoding speed: converting images to AVIF takes significantly longer than WebP or JPEG. This makes it best suited for static assets that are compressed once at build time rather than on-the-fly.

When to Use Each Format

  • Photographs and complex images: Use AVIF as the primary format with WebP as a fallback and JPEG as the final fallback
  • Simple graphics with few colors: PNG or SVG (SVG for vector graphics)
  • Icons and logos: SVG whenever possible — it scales to any size without quality loss and is typically very small
  • Animations: WebP or AVIF to replace animated GIFs, or consider using a short video (<video>) for longer animations
  • Transparency needed: WebP, AVIF, PNG, or SVG — not JPEG, which doesn't support alpha channels
Tip: You don't have to choose a single format. The <picture> element lets you serve the best format each browser supports, with automatic fallback for older browsers.

Responsive Images

A single image cannot serve every device well. A 2000px-wide hero image is wasted on a 375px-wide phone screen, transferring megabytes of data the user will never see. Responsive images solve this by letting you provide multiple versions of an image and letting the browser choose the best one.

The srcset and sizes Attributes

The srcset attribute on an <img> element provides a list of image sources with their widths. The sizes attribute tells the browser how wide the image will be displayed at different viewport sizes. The browser uses both pieces of information to select the optimal image.

<img
  src="hero-800.jpg"
  srcset="hero-400.jpg 400w,
          hero-800.jpg 800w,
          hero-1200.jpg 1200w,
          hero-1600.jpg 1600w"
  sizes="(max-width: 600px) 100vw,
         (max-width: 1200px) 80vw,
         1200px"
  alt="A descriptive alt text"
  width="1600"
  height="900">

In this example, on a phone screen the browser knows the image fills the full viewport width (100vw), so it picks the 400w version. On a larger screen where the image is 1200px wide, it picks the 1200w version. The browser also factors in device pixel ratio — a Retina display at 800px viewport width would pick the 1600w version for crisp rendering.

The picture Element

The <picture> element provides even more control. It lets you specify different image sources based on media queries, format support, or both. This is called art direction — you can serve a cropped portrait version on mobile and a wide landscape version on desktop.

<picture>
  <source
    type="image/avif"
    srcset="hero.avif">
  <source
    type="image/webp"
    srcset="hero.webp">
  <source
    media="(max-width: 600px)"
    srcset="hero-mobile.jpg">
  <img
    src="hero.jpg"
    alt="A descriptive alt text"
    width="1600"
    height="900">
</picture>

The browser evaluates <source> elements in order and uses the first one that matches. If none match (or the browser doesn't support <picture>), it falls back to the <img> element.

Preventing Layout Shift with Proper Dimensions

One of the most common causes of Cumulative Layout Shift (CLS) is images that load without reserved space. When the browser doesn't know an image's dimensions in advance, it renders the surrounding content first, then shifts everything when the image arrives.

The fix is simple: always include width and height attributes on your <img> elements. Modern browsers use these attributes to calculate the aspect ratio and reserve the correct amount of space before the image loads, even if CSS resizes the image responsively.

<!-- Good: browser reserves space -->
<img src="photo.jpg" alt="Description" width="800" height="600">

<!-- CSS makes it responsive while preserving aspect ratio -->
<style>
  img {
    max-width: 100%;
    height: auto;
  }
</style>

The combination of explicit dimensions in HTML and max-width: 100%; height: auto; in CSS gives you responsive images that never cause layout shifts.

Warning: If your CSS sets a fixed height on images (e.g., height: 300px), the aspect ratio from the HTML attributes will be overridden. Use aspect-ratio in CSS or object-fit for more control over how images fill their containers.

Compression Tools

Even after choosing the right format, you should compress images to find the sweet spot between quality and file size. Most images can lose 20-50% of their file size with no perceptible quality difference.

  • Squoosh (squoosh.app) — Google's browser-based tool that lets you visually compare compression levels across formats. Excellent for understanding the quality/size tradeoff.
  • ImageOptim — a macOS application that losslessly strips metadata and applies optimal compression to JPEG, PNG, and GIF files. Great for batch processing.
  • Sharp — a high-performance Node.js library for resizing and converting images. Ideal for build pipelines and server-side image processing. It uses libvips under the hood and is significantly faster than ImageMagick.
  • SVGO — an SVG optimizer that removes unnecessary metadata, comments, and attributes from SVG files, often reducing their size by 30-50%.

SVG for Icons and Simple Graphics

SVG (Scalable Vector Graphics) deserves special attention. Unlike raster formats (JPEG, PNG, WebP), SVG is a vector format that describes shapes mathematically. This means:

  • Resolution independent — SVGs look sharp at any size, on any screen density
  • Typically tiny — a simple icon might be 500 bytes as SVG versus 5KB as a PNG
  • Styleable with CSS — you can change colors, sizes, and animations with CSS when SVGs are inlined
  • Accessible — SVGs support <title> and <desc> elements for screen readers

Use SVG for icons, logos, illustrations, and any graphic composed of simple shapes. Use raster formats for photographs and complex imagery where vector representation would be impractically large.

Image Optimization Checklist

A practical checklist for optimizing images on any project:

  1. Serve AVIF with WebP fallback for photographs using the <picture> element
  2. Use SVG for all icons and simple graphics
  3. Add width and height attributes to every <img> element
  4. Provide responsive images with srcset and sizes for images that span different widths across breakpoints
  5. Compress all images — aim for the lowest file size where quality loss is imperceptible
  6. Lazy load below-the-fold images (covered in the Lazy Loading lesson)
  7. Use fetchpriority="high" on the LCP image to tell the browser it's the most important resource
  8. Optimize SVGs with SVGO to remove unnecessary metadata

Resources