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.
-
Architecture That Scales
-
Modern CSS Without a Framework Crutch
-
Cascade Layers and Specificity You Control
-
-
-
Layout Systems for Real Sites
-
Complex Grids and Nested Layout Patterns
-
Container Queries When the Component Is the Breakpoint
-
-
-
Motion and Interaction Done Right
-
Transitions and Animations That Don't Annoy People
-
prefers-reduced-motion and Respecting the User
-
-
-
Performance and Delivery
-
Critical CSS and What Blocks First Paint
-
Font Loading Without Layout Jump
-
Responsive Images: srcset, sizes and Lazy Load
-
-
-
Ship and Maintain
-
Design Tokens and Theming Without Duplicating Everything
-
CSS That Survives a Redesign
-
Audit Accessibility and Visual Regressions Before Launch
-
-
- Final Check: HTML and CSS Advanced
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">
srcsetwithwlists each file and its real width in pixels.sizessays 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.widthandheightgive the browser the aspect ratio, so it reserves the space before the file arrives. Without them the page jumps when the image appears.srcis the fallback for browsers that do not understandsrcset.
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
xdescriptors (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
widthandheightbecause CSS setswidth: 100%. Add them and keepheight: autoin 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
Comments (0)
Sign in to commentNo comments yet.