Skip to content

Responsive Images Craft

When to Use

Use srcset+sizes on <img> when serving the same crop at different sizes. Use <picture> with <source media> when you need different crops or compositions per breakpoint (art direction). Use <picture> with <source type> for format fallback chains.

Decision

If you need... Use... Why
Same image, different resolutions (1x/2x) srcset with density descriptors (1x, 2x) Browser picks density match; no math needed
Same image, different widths for different viewports srcset with width descriptors (400w, 800w) + sizes Browser picks best width based on sizes hint
Completely different crops per breakpoint <picture> + <source media="..."> Forces specific image at specific breakpoint
Format fallback (AVIF → WebP → JPEG) <picture> + <source type="..."> Browser picks first supported format
Art direction AND format fallback <picture> with both type and media on <source> Combine both axes

Image breakpoint strategy: Image breakpoints are not the same as CSS layout breakpoints. Choose based on file size jumps (~30% steps): 1920 → 1280 → 900 → 600 → 400. For hero images: 2560, 1920, 1280, 900, 640. For card grids: 800, 600, 400, 300.

Pattern

Resolution switching (most common):

<img
  srcset="hero-640.jpg 640w, hero-1280.jpg 1280w, hero-1920.jpg 1920w"
  sizes="(max-width: 640px) 100vw, (max-width: 1280px) 80vw, 1200px"
  src="hero-1280.jpg"
  alt="Descriptive alt text"
  width="1280"
  height="720"
>

Art direction (different crop per breakpoint):

<picture>
  <source
    media="(max-width: 640px)"
    srcset="hero-mobile-640.jpg 640w, hero-mobile-1280.jpg 1280w"
    sizes="100vw"
  >
  <source
    media="(min-width: 641px)"
    srcset="hero-desktop-1280.jpg 1280w, hero-desktop-1920.jpg 1920w"
    sizes="(max-width: 1280px) 80vw, 1200px"
  >
  <img src="hero-desktop-1280.jpg" alt="..." width="1280" height="720">
</picture>

sizes calculation — describes the image's rendered width at each viewport: - 100vw = full-width image - (max-width: 768px) 100vw, 50vw = full-width on mobile, half on desktop - (max-width: 640px) calc(100vw - 32px), (max-width: 1024px) 50vw, 400px = accounts for padding

sizes does not control layout — CSS controls layout. Mismatching sizes and CSS wastes bandwidth.

Common Mistakes

  • Wrong: density descriptors (2x) for layout images → Right: use width descriptors (w); density descriptors are for fixed-size UI elements only
  • Wrong: sizes="100vw" on a card that's 33vw on desktop → Right: match sizes to the actual rendered width
  • Wrong: omitting width and height attributes → Right: always include; browser needs them to reserve space and prevent CLS
  • Wrong: <picture> for resolution switching → Right: srcset+sizes on <img> is simpler; <picture> is for art direction or format fallback

See Also