Modern HTML5 in Production · Loading Performance
Responsive Images: Sending the Right Bytes
Why a news site's pages downloaded about 6.6 MB of images on every device, and how srcset, sizes and modern formats cut that by 55 to 85%.
Scenario
Example app: a news site uploads photos at 2400 pixels wide and uses the same file everywhere: <img src="photo-2400.jpg">. On phones, articles show photos about 400 CSS pixels wide.
What you see in production
- Average mobile article weight is about 6.6 MB, mostly images; pages are slow on 4G and expensive for users on metered data.
- Lighthouse reports "Properly size images" with large potential savings.
The naive code
<img src="/photos/storm-2400.jpg" alt="Storm over the harbour" width="2400" height="1600">
Reproduce it
The browser picks a candidate from srcset based on the image's displayed width (from sizes) multiplied by the screen's pixel density. The simulation applies that rule for three devices and compares downloaded bytes with the single large file.
const candidates = [ // width in pixels, approximate JPEG size in KB
{ w: 480, kb: 45 }, { w: 800, kb: 110 }, { w: 1200, kb: 220 }, { w: 1600, kb: 380 }, { w: 2400, kb: 820 },
];
const devices = [
{ name: "phone", viewport: 390, dpr: 3 },
{ name: "tablet", viewport: 820, dpr: 2 },
{ name: "laptop", viewport: 1440, dpr: 1 },
];
// sizes="(max-width: 700px) 100vw, 700px": full width on small screens, 700px column otherwise
const displayedWidth = (vw) => (vw <= 700 ? vw : 700);
const imagesPerArticle = 8;
for (const d of devices) {
const needed = displayedWidth(d.viewport) * d.dpr;
const pick = candidates.find((c) => c.w >= needed) ?? candidates[candidates.length - 1];
const naive = candidates[candidates.length - 1];
console.log(`${d.name.padEnd(7)} needs ${String(needed).padStart(4)}px -> ${pick.w}w (${pick.kb} KB) vs ${naive.kb} KB; ` +
`per article: ${(pick.kb * imagesPerArticle / 1000).toFixed(1)} MB vs ${(naive.kb * imagesPerArticle / 1000).toFixed(1)} MB`);
}
Output
phone needs 1170px -> 1200w (220 KB) vs 820 KB; per article: 1.8 MB vs 6.6 MB tablet needs 1400px -> 1600w (380 KB) vs 820 KB; per article: 3.0 MB vs 6.6 MB laptop needs 700px -> 800w (110 KB) vs 820 KB; per article: 0.9 MB vs 6.6 MB
High-density phones still need fairly large images. Many sites cap the density they serve (around 2x), and modern formats like AVIF and WebP cut sizes further.
Root cause
One file for every screen means small screens download pixels they can't display. The browser can only choose a better file if the HTML offers alternatives and says how wide the image is displayed.
The fix
- Generate several widths (for example 480, 800, 1200, 1600) when images are uploaded, or use an image CDN.
- Use
srcsetwithwdescriptors plus an accuratesizesattribute matching your CSS layout. - Offer AVIF/WebP via
<picture>with a JPEG fallback. - Keep
width/heightfor layout stability. See responsive images on MDN.
Trade-offs
- More variants mean more storage and processing; image CDNs move that cost to a service.
- A wrong
sizesvalue makes the browser pick badly; keep it in sync with the CSS.
Detect it in production
- Track page weight by device type; Lighthouse's "Properly size images" and "Serve images in modern formats" audits.
- Check in DevTools which
srcsetcandidate was downloaded (the image'scurrentSrc).
Key points
- Offer multiple sizes with
srcsetand describe the layout withsizes. - Use modern formats with
<picture>fallbacks. - Measure image bytes per device type.
Practice questions
How does a browser choose an image from srcset with w descriptors?
Answer
It works out the displayed width from the sizes attribute, multiplies by the device pixel ratio, and picks a candidate at least that wide (it may also consider network conditions and cache).
What is the sizes attribute for?
Answer
It tells the browser how wide the image will be displayed at different viewport widths, before CSS is loaded, so it can choose the right srcset candidate.
When would you use the picture element instead of only srcset?
Answer
For different formats (AVIF, WebP with JPEG fallback) or for art direction (a different crop on small screens); srcset alone only switches resolutions of the same image.
Open in the app to mark lessons complete, take notes and track your progress.