Skip to content

Responsive Images

Images are the single most common cause of broken responsive layouts. A 1200-px-wide photo dropped into a 375-px-wide phone will overflow the screen and cause horizontal scrolling. Fixing this is one line of CSS — but understanding why it works (and how to go further) makes you a much better designer-developer.

img {
max-width: 100%;
height: auto;
}
  • max-width: 100% — the image can never be wider than its container. If the container shrinks, the image shrinks with it.
  • height: auto — the browser recalculates the height automatically to keep the image’s aspect ratio. Without this, images would stretch vertically.

This is so fundamental that most CSS resets and frameworks (like Tailwind) include it by default.

The preview shows two images (represented by coloured boxes for illustration). The first has no max-width constraint; the second has max-width: 100%. Narrow the preview pane to see what happens.

When the pane is narrow, the red box overflows its container — that is what a fixed-size image does on mobile. The green box respects the container boundary and shrinks gracefully.

max-width: 100% makes the image look smaller on small screens. It does not make the file smaller. A 3-MB photograph is still 3 MB even when it displays at 375 px wide — it just arrives slowly over a mobile data connection.

The srcset attribute lets you provide multiple versions of an image. The browser picks the best one for the device:

<img
src="hero-800.jpg"
srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1600.jpg 1600w"
sizes="(max-width: 480px) 100vw, 800px"
alt="Hero image description"
/>
  • 400w, 800w, 1600w — the actual pixel width of each file.
  • sizes — tells the browser how wide the image will be displayed at different breakpoints, so it can pick the right source before downloading.

You do not need to implement srcset by hand in most projects — tools like Next.js <Image>, Astro’s <Image>, or Cloudinary handle it automatically. The important thing to understand is the concept: export images at multiple sizes, and let the browser choose.

When you want to show a different crop or composition on mobile versus desktop (not just a smaller version of the same image), use the <picture> element:

<picture>
<source media="(max-width: 480px)" srcset="hero-portrait.jpg" />
<img src="hero-landscape.jpg" alt="Hero image" />
</picture>

This is the direct code equivalent of having different image crops in your Figma mobile and desktop artboards.

What does `max-width: 100%` on an image do?
Why is `height: auto` added alongside `max-width: 100%`?
What is the difference between using srcset and just using max-width: 100%?
When would you use the `<picture>` element instead of just `srcset`?