# Responsive Images with srcset and sizes

Offer the same photo in several widths with srcset, tell the browser how wide it will be shown with sizes, and let each phone, laptop and sharp screen download the file it needs.

Journeyman · HTML · Web Development · Updated October 31, 2026

## After this lesson you can

- Offer one picture in several widths with srcset and w descriptors, and say how wide it's shown with sizes
- Offer a fixed-size picture for sharper screens with x descriptors

## Key takeaways

- srcset lists copies of one picture, each with a w descriptor that says how wide the file is, such as 960w.
- sizes tells the browser how wide the picture will be shown, because it chooses a file before it reads the page's styles.
- The browser multiplies the shown width by the screen's sharpness and picks the closest file, usually the next size up.
- For a picture shown at one fixed size, x descriptors (1x, 2x) offer a sharper copy for sharper screens.
- The Network panel shows which file the browser chose.

The same travel blog post gets read on a phone on the bus and on a big monitor at home. Give everyone the 1600-pixel lighthouse photo, and the phone downloads 180 KB to show a picture 400 pixels wide. Give everyone the 480-pixel copy, and the monitor stretches it into a blur. You don't have to pick one: HTML lets you offer several copies of a picture and lets each device download the one it needs. A picture set up this way is called a **responsive image**, and it's how every big news site, shop and photo site serves its pictures.

## The same photo, three sizes

A T-shirt shop doesn't make one size and hope. It hangs small, medium and large on the rack, and each customer takes the one that fits. You can do the same with a photo: save it in a few widths, and hang them all on the "rack" for the browser to choose from.

The travel blog's lighthouse photo comes in three copies, named by their widths in pixels:

```text
lighthouse-480.jpg     480 × 360     27 KB
lighthouse-960.jpg     960 × 720     80 KB
lighthouse-1600.jpg   1600 × 1200   180 KB
```

Three is a good number to start with: one for small phones, one for most phones and laptops, and one for big and sharp screens.

## srcset and w descriptors

The **`srcset`** attribute, read "source set", lists the copies. Each entry is a file, a space, and its width followed by `w`. That `w` label is a **width descriptor**: `960w` (read "nine-sixty w") means "this file is 960 pixels wide". Commas go between the entries.

```html
<img src="images/lighthouse-960.jpg"
     srcset="images/lighthouse-480.jpg 480w,
             images/lighthouse-960.jpg 960w,
             images/lighthouse-1600.jpg 1600w"
     alt="The white lighthouse with its red lantern room"
     width="1600" height="1200">
```

- **The number after the file is the file's real width**, not how wide you'd like it shown. A label on the box, like the M on a T-shirt.
- **`src` stays.** It's the backup for a browser that doesn't understand `srcset`. The middle size is a good choice.
- **Line breaks inside the attribute are fine.** They keep a long list readable.

## sizes: how wide the picture is shown

The browser chooses a file before it has read the page's stylesheet: it starts downloading pictures as early as it can, so they arrive sooner. That means it doesn't know yet how wide the picture will be on screen. The **`sizes`** attribute tells it.

On the travel blog, a photo fills the screen on a phone, but the story column never gets wider than 720 pixels. Written as `sizes`:

```html
sizes="(max-width: 720px) 100vw, 720px"
```

Read it from left to right, like a sign with directions:

- **`(max-width: 720px) 100vw`**: "when the screen is at most 720 pixels wide, the picture is the full width of the screen". `vw` stands for **viewport width**: the **viewport** is the part of the browser window that shows the page, and `100vw` (read "a hundred v-w") is all of its width. `50vw` would be half.
- **`720px`**: "otherwise, the picture is 720 pixels wide". The last entry has no condition: it's the answer when no earlier one matched.

Close is good enough: `sizes` is a hint for choosing a file, not a ruler. Without `sizes`, the browser assumes the picture fills the whole width of the window, `100vw`, which picks too big a file for a picture in a column.

## How the browser picks

The browser does a small sum: **the shown width × the screen's sharpness**. A sharp screen draws each pixel of the page with 2 or 3 of its own dots (its **pixel density**, written `2x` or `3x`), so it needs a file 2 or 3 times as wide to look crisp. Then it picks the copy closest to that, usually the next size up:

| Screen | Shown width | × density | Needs | Picks |
|---|---|---|---|---|
| A laptop | 720 | × 1 | 720 pixels | `lighthouse-960.jpg` |
| A laptop with a sharp screen | 720 | × 2 | 1440 pixels | `lighthouse-1600.jpg` |
| A phone, 400 wide | 400 | × 2 | 800 pixels | `lighthouse-960.jpg` |

The full `<img>`, with `srcset` and `sizes` together:

```html
<img src="images/lighthouse-960.jpg"
     srcset="images/lighthouse-480.jpg 480w, images/lighthouse-960.jpg 960w, images/lighthouse-1600.jpg 1600w"
     sizes="(max-width: 720px) 100vw, 720px"
     alt="The white lighthouse with its red lantern room"
     width="1600" height="1200" loading="lazy">
```

The final choice is the browser's. For a close call, it may round down to the smaller file, and if it already has the bigger copy from an earlier visit, it may use that instead of downloading a smaller one. You offer the choices; the browser knows things about the screen and the connection that you don't.

## x descriptors for a picture with a fixed size

Some pictures are the same size on every screen: the blog's writer, Marisol, has a round profile photo that's 120 pixels wide on a phone and on a monitor. Its shown width never changes, so all the browser needs to know is how sharp the screen is. For that, `srcset` takes a **pixel density descriptor** instead: `1x` (read "one x") for ordinary screens and `2x` for sharp ones.

```html
<img src="images/marisol-120.jpg"
     srcset="images/marisol-120.jpg 1x, images/marisol-240.jpg 2x"
     alt="Marisol, smiling, in a sun hat on the beach"
     width="120" height="120">
```

- **No `sizes` with x descriptors.** The size is fixed, so there's nothing to describe.
- **Don't mix the two kinds.** One `srcset` uses `w` or `x`, never both.
- **A logo that isn't an SVG** works the same way. An SVG logo needs neither: it's sharp at any size.

## See which file the browser chose

1. Open the page, press **F12**, and choose the **Network** panel.
2. Tick **Disable cache** (so the browser can't reuse a copy it already has), and choose the **Img** filter.
3. Turn on the device toolbar with **Ctrl+Shift+M** (**Cmd+Shift+M** on a Mac), choose a phone from the list at the top, and reload.

The list shows the file the browser downloaded for that screen, and its size. Choose a bigger device, reload, and watch the file change. In the **Elements** panel, holding the mouse over the `<img>` also shows its **current source**: the file it's showing right now.

![The Network panel with the Img filter on, listing lighthouse-960.jpg at 80 KB for a phone-sized screen](https://www.ask-codey.com/lessons/TODO)

**Try it.** Take one photo of your own and make 480, 960 and 1600-pixel copies with Squoosh (see *Image Formats and File Size*). Put them on a page with `srcset` and `sizes="100vw"`, then use the device toolbar to find a screen that picks each one.

## Check yourself

2 questions to try on the lesson page.

## So what

With `srcset` and `sizes`, one line of HTML serves a small file to a phone on the bus and a crisp one to a big screen, and the browser does the choosing every time.

## Key terms

- [Responsive image](https://www.ask-codey.com/glossary/responsive-image)
- [srcset](https://www.ask-codey.com/glossary/srcset)
- [sizes](https://www.ask-codey.com/glossary/sizes)
- [Width descriptor](https://www.ask-codey.com/glossary/width-descriptor)
- [Pixel density descriptor](https://www.ask-codey.com/glossary/pixel-density-descriptor)

## Cheat sheets

- [Responsive Images with srcset and sizes](https://www.ask-codey.com/cheat-sheets/html-images-srcset-and-sizes-cheat-sheet)

## Related

- [Image Dimensions and Lazy Loading](https://www.ask-codey.com/lessons/html-images-dimensions-and-lazy-loading)
- [The Picture Element](https://www.ask-codey.com/lessons/html-images-the-picture-element)

Source: https://www.ask-codey.com/lessons/html-images-srcset-and-sizes
