↑↓ to move ↵ to open Esc to close Browse all tools

Images guide

Responsive Images: srcset, sizes and Which Widths to Export

A phone on a slow connection and a 5K monitor should not download the same photo. srcset and sizes let the browser choose a file that fits the space and the screen density, and the picture element adds different crops and formats. Here is how the attributes work, what the browser actually does with them, and a practical set of sizes to export.

Two problems, two tools

MDN separates the subject into two problems. Resolution switching means serving the same picture in several resolutions and letting the browser pick one for the screen size and pixel density. Art direction means serving a different picture, usually a tighter crop, when the layout is narrow, because a wide landscape shot shrunk to a phone column shows nothing useful. The first problem is solved by two attributes on the img element; the second needs the picture element.

srcset and sizes, line by line

<img
  srcset="photo-400.jpg 400w,
          photo-800.jpg 800w,
          photo-1600.jpg 1600w"
  sizes="(width <= 600px) 100vw, 800px"
  src="photo-800.jpg"
  alt="Harbour at dusk">
  • srcset lists the candidate files, each followed by its real pixel width and the unit w. The browser learns what it could load and how big each file is before it downloads anything.
  • sizes lists media conditions, each paired with the width the image will occupy when the condition is true, and a final default with no condition. Here the image fills the viewport up to 600 px wide and sits in an 800 px slot otherwise. MDN warns that the browser stops at the first condition that matches, so order them from narrow to wide.
  • src is the fallback for browsers that do not understand the other two attributes, and alt is the text alternative; the alt text guide covers it.

What the browser does with this: it evaluates sizes to find the slot width, multiplies by the device pixel ratio, and picks the file closest to that. MDN describes the rule when there is no exact match: the browser chooses the first file that is bigger than the slot and scales it down. A 400 px slot on a 2× phone wants 800 pixels, so it loads photo-800.jpg; the same slot on a 1× screen loads photo-400.jpg.

Fixed-size images: x descriptors

When an image is always displayed at the same CSS size, a logo at 200 px say, there is nothing for sizes to do, and srcset can list densities instead of widths:

<img srcset="logo-200.png, logo-300.png 1.5x, logo-400.png 2x"
     src="logo-400.png" alt="Freebiefy" width="200" height="60">

The browser loads the first file on a standard-density screen and the 2x file where there are two device pixels per CSS pixel. Do not mix x and w descriptors in one srcset.

picture: different crops and different formats

The picture element wraps one or more source elements and ends with an img. The browser walks the sources in order and takes the first one it can use; the img is both the default and the fallback for browsers that do not support picture, and MDN says that without it nothing is displayed at all.

<picture>
  <source media="(width < 800px)" srcset="hero-portrait.jpg">
  <source media="(width >= 800px)" srcset="hero-wide.jpg">
  <img src="hero-wide.jpg" alt="Team at the workshop">
</picture>

That is art direction: a portrait crop on narrow screens, the wide shot elsewhere. MDN's advice is to use the media attribute only for art direction, and not to repeat media conditions inside sizes when you do.

The same element handles format fallback through the type attribute. A source whose MIME type the browser does not support is skipped:

<picture>
  <source type="image/avif" srcset="photo-800.avif 800w, photo-1600.avif 1600w" sizes="(width <= 600px) 100vw, 800px">
  <source type="image/webp" srcset="photo-800.webp 800w, photo-1600.webp 1600w" sizes="(width <= 600px) 100vw, 800px">
  <img srcset="photo-800.jpg 800w, photo-1600.jpg 1600w" sizes="(width <= 600px) 100vw, 800px" src="photo-800.jpg" alt="Harbour at dusk">
</picture>

Browsers that read AVIF take the first source, the rest fall through to WebP and then JPEG. The format guide explains when the newer formats pay off; the JPG to WebP converter and the WebP converter produce the alternates.

Why not CSS or JavaScript

MDN's explanation is about timing. The browser's preloader fetches images as soon as it sees the img tag, before the stylesheet or any script has run. A script that measures the viewport and swaps in a smaller file acts too late: the large file is already downloading, and the small one is now a second request. srcset, sizes and picture are read by the preloader itself, which is the only point at which the choice saves anything.

Which widths to export

For an image that fills a content column up to 800 CSS pixels wide, four files cover the common cases:

Export widthCoversTypical device
400 px800 px slot at 0.5× densityPhone at 1×, 400 px wide column
800 px800 px slot at 1.0× densityLaptop at 1×, or 400 px column at 2×
1200 px800 px slot at 1.5× densityPhone at 3× on a 400 px column
1600 px800 px slot at 2.0× densityLaptop at 2×

Each step is 1.5 to 2 times the previous width, which keeps the browser's "first file bigger than the slot" rule from wasting much. The image resizer exports a photo at each width, and the image compressor brings each file down afterwards; compress the originals once, then resize, so every size starts from the best source. For icons and line art, a single SVG replaces the whole set, because vectors scale without a file per width.

Checklist

  1. Every content image has srcset with w descriptors and a sizes attribute that matches the layout.
  2. Fixed-size images use x descriptors instead.
  3. Different crops use picture with media; different formats use picture with type, AVIF before WebP before JPEG, and img last.
  4. Width and height attributes are set so the page does not jump when the image loads; the Core Web Vitals guide explains why that matters.
  5. The widths you export step up by 1.5 to 2×, and the largest is no bigger than the biggest slot at 2×.

Frequently asked questions

What is a responsive image?

An image that is delivered at a size suited to the device showing it. MDN describes two problems a responsive image solves: resolution switching, where the browser picks the right file for the screen size and pixel density, and art direction, where it shows a different crop on a narrow screen. The first is handled by srcset and sizes, the second by the picture element.

What is the difference between srcset and sizes?

srcset lists the files and tells the browser how wide each one is, in pixels, with a w descriptor. sizes tells the browser how wide the image will be displayed under each media condition. The browser combines the two with the screen's pixel density to choose the smallest file that is still sharp.

Can I do this with CSS or JavaScript instead?

Not well. MDN explains that browsers start loading images before CSS and JavaScript have been parsed, so a script that swaps a smaller file in later has already downloaded the large one, and now loads a second file as well. srcset and sizes work because the browser reads them during that early preload.

How many sizes should I export?

Enough that the gap between neighbours is not wasteful, not so many that the build and the HTML balloon. Three or four widths, each roughly 1.5 to 2 times the previous one, cover phones at 1× through laptops at 2× for a typical content column; the table in this guide shows one such set. The image resizer exports any width you need.

Does srcset also handle WebP and AVIF?

Not by itself. Format fallback is the picture element's job: each source element carries a type attribute with the MIME type, and MDN says a source whose type the browser does not support is skipped, so you list AVIF first, WebP second and the img with a JPEG last. Each source can still have its own srcset and sizes.

Sources