Skip to Content
HTML and CSS Advanced: Styles That Hold Up in Production
Advanced
0 likes
Courses
HTML and CSS Advanced: Styles That Hold Up in Production

Responsive Images: srcset, sizes and Lazy Load

Write srcset and sizes that match the layout, reserve space with width and height, and lazy load only what is off screen. After this, phones stop downloading desktop images.

Course content

Sign in to save your progress.

Course Home

Skip ahead: If you already write srcset with width descriptors, a truthful sizes, and width and height on every image, skip to "Lazy loading, and where not to use it", then continue.

Images are usually the heaviest thing on a page, and the usual mistake is one big file for every screen. A phone on a small screen downloads the same pixels as a 4K monitor. srcset and sizes fix that by giving the browser a list of files and a way to work out which one it needs. The browser makes the choice. You supply the facts.

The markup

<img
  src="product-800.jpg"
  srcset="product-400.jpg 400w, product-800.jpg 800w, product-1200.jpg 1200w"
  sizes="(min-width: 960px) 25vw, (min-width: 600px) 50vw, 100vw"
  width="800" height="480"
  alt="Blue product tile">
  • srcset with w lists each file and its real width in pixels.
  • sizes says how wide the image will be on screen, before the CSS has loaded. It is read left to right and the first match wins. The last value, with no condition, is the fallback.
  • width and height give the browser the aspect ratio, so it reserves the space before the file arrives. Without them the page jumps when the image appears.
  • src is the fallback for browsers that do not understand srcset.

What the browser picked

I put that image in a grid that is one column below 600px, two columns from 600px and four from 960px, then asked Chrome 154 which file it chose, for different windows and screen densities.

viewport  390px, DPR 2: slot 342px -> product-800.jpg
viewport  390px, DPR 3: slot 342px -> product-1200.jpg
viewport  768px, DPR 1: slot 352px -> product-400.jpg
viewport 1280px, DPR 1: slot 296px -> product-400.jpg
viewport 1280px, DPR 2: slot 296px -> product-800.jpg

The same slot, 342px, needs a bigger file on a screen with twice or three times as many pixels per CSS pixel. That is why the list has three widths and not one.

sizes must match the layout

My first version of the test grid used auto-fit columns with only two items, so each column stretched and the image slot was 608px wide at 1280px. My sizes still said 25vw, which is 320px. Chrome believed me and chose the 400px file, then stretched it to 608px. The browser cannot see your layout. If the CSS changes, sizes has to change with it.

⚠ Warning: Changing a grid from four columns to three and forgetting sizes gives you blurry images that look fine in the code review. Keep the two in the same pull request.

Lazy loading, and where not to use it

<img src="gallery-9.jpg" loading="lazy" width="800" height="480" alt="...">

loading="lazy" defers images that are far from the viewport. I tested it: a 400px image at the top loaded at once, and an 800px image 3000px lower was only requested after I scrolled down. Do not put it on the main image at the top of the page. That image is usually what the page is judged on, so it should load first. Give it fetchpriority="high" instead.

picture for different crops or formats

Use <picture> when the picture itself must change, such as a wide crop on desktop and a tight crop on a phone, or a newer format with a fallback. For the same picture at different sizes, srcset is enough.

Common mistakes

  • Using x descriptors (2x, 3x) for images whose size changes with the layout. Width descriptors are what that needs.
  • Listing widths the files do not actually have. The browser trusts the number you wrote.
  • Lazy loading everything, including the first screen.
  • Leaving off width and height because CSS sets width: 100%. Add them and keep height: auto in CSS.

💡 Tip: Generate the size variants in your build. A hand-made list of files will drift from the markup.

What happens if you skip this

Phones download desktop images over mobile data, and the page pays for it twice, in speed and in data the visitor paid for. Meanwhile the images without dimensions push the text down as they arrive.

Try it

Open DevTools on one product page, run document.querySelector('img').currentSrc in the console, and resize the window. Does the file change when you expect it to?

Does your sizes describe the layout you have today, or the one you had last year?

About

Write srcset and sizes that match the layout, reserve space with width and height, and lazy load only what is off screen. After this, phones stop downloading desktop images.

Duration
5 min
Last update
08/02/2026
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.