Skip to main content
Back to module
Accessible & Responsive Interfaces · Responsive Design

Responsive images

Reading1h 10mLesson 3 of 3 in this module

What you'll learn

  • Serve the right image size
  • Prevent layout shift with width and height attributes
  • Offer modern formats and art direction with picture and source
  • Lazy-load images below the fold but never the hero

Serve the right image size and format with srcset, sizes, picture and lazy loading.

Why this matters

Images are usually the heaviest part of a page. Sending a 2400 px wide photo to a 360 px phone wastes data and slows the page, which hits people on prepaid plans and slow connections hardest. Images without dimensions also make the page jump as they load (layout shift), which is disorienting for everyone and especially for people with cognitive or vision impairments who lose their place. HTML has built-in tools for all of this.

Step 1: let images shrink

CSS
img { max-width: 100%; height: auto; }

max-width: 100% stops an image overflowing its container; height: auto keeps the aspect ratio. Put this in every stylesheet.

Step 2: always set width and height

HTML
<img src="trail-800.jpg" width="1600" height="900" alt="Hikers on a ridge at sunrise">

The numbers are the image's intrinsic size (or any pair with the same ratio). Browsers use them to reserve the right space before the file arrives, and the CSS above still makes it responsive. This is the single biggest fix for Cumulative Layout Shift. CSS aspect-ratio does the same job for elements without intrinsic dimensions.

Step 3: srcset and sizes (resolution switching)

When the same picture is needed at different sizes, offer several files and let the browser choose:

HTML
<img
  src="trail-800.jpg"
  srcset="trail-480.jpg 480w, trail-800.jpg 800w, trail-1600.jpg 1600w"
  sizes="(min-width: 60rem) 50vw, 100vw"
  width="1600" height="900"
  alt="Hikers on a ridge at sunrise">
  • srcset lists files with their real widths (480w means 480 pixels wide).
  • sizes tells the browser how wide the image will be displayed: half the viewport on wide screens, the full viewport otherwise. The browser needs this before CSS loads.
  • The browser multiplies the display width by the screen's pixel density and picks the smallest file that is big enough. A phone at 360 px and 3x density needs about 1080 px, so it takes trail-1600.jpg; a 1x laptop showing it at 600 px takes trail-800.jpg.
  • src is the fallback for very old browsers.

For a fixed-size image (like an avatar) use density descriptors instead: srcset="avatar.jpg 1x, avatar@2x.jpg 2x".

Step 4: picture for formats and art direction

<picture> lets you offer modern formats with a fallback, or a different crop at different sizes:

HTML
<picture>
  <source type="image/avif" srcset="team.avif">
  <source type="image/webp" srcset="team.webp">
  <img src="team.jpg" width="1200" height="800" alt="The support team at their desks">
</picture>

The browser uses the first <source> it supports. The <img> inside is required: it is what actually renders, and it carries alt, width, height and loading. For art direction, add media to a source, for example a tight square crop for phones:

HTML
<picture>
  <source media="(min-width: 40rem)" srcset="banner-wide.jpg">
  <img src="banner-square.jpg" width="800" height="800" alt="A bowl of ramen">
</picture>

Step 5: lazy-load what is off screen

HTML
<img src="gallery-3.jpg" loading="lazy" width="800" height="600" alt="...">

loading="lazy" delays images below the fold until the user scrolls near them. Do not lazy-load the main image at the top of the page (often the Largest Contentful Paint element); it should load immediately, and fetchpriority="high" can help it start sooner.

Alt text still matters

Every responsive technique above is about the file. The alt attribute is still what screen reader users get, and it goes on the <img>, not on <source>. Describe what the image conveys in context; use alt="" for decorative images. A chart or diagram needs a text equivalent nearby (a sentence or a data table) when alt is not enough.

Worked example: a recipe page

The page has a hero photo, a step-by-step gallery of six photos further down and a decorative divider. A good result:

  • Hero: srcset with 3 widths, sizes="100vw", width/height, no loading="lazy", a descriptive alt.
  • Gallery: loading="lazy", width/height, alt text for each step ("Folding the dough in half").
  • A <picture> for the hero offering AVIF and WebP before the JPEG.
  • Divider: alt="" or, better, a CSS border.

Common mistakes

  • srcset with w descriptors but no sizes: the browser assumes 100vw and may download a file far too big.
  • Missing width and height, causing layout shift.
  • Lazy-loading the hero image.
  • Putting alt on <picture> or <source> (it belongs on <img>).
  • Using CSS background images for content images, which have no alt text.

Quick recap

  • img { max-width: 100%; height: auto; } plus width/height attributes.
  • srcset + sizes for resolution switching; <picture> for formats and art direction.
  • loading="lazy" below the fold only.
  • alt on the <img>, always.
  • Reference: MDN: Responsive images and W3C WAI Images tutorial.

Try it

Open the Do tab and make a gallery page's images responsive. (The preview has no network, so images show as broken; the checks look at your markup and CSS.)

Key terms (5)

srcset
An img attribute listing candidate files with their widths (or densities) so the browser can choose the best one.
sizes
An img attribute telling the browser how wide the image will be displayed, so it can pick from srcset before CSS loads.
layout shift
Content jumping as images load because no space was reserved; width and height attributes prevent it.
art direction
Serving a different crop or image at different screen sizes, done with media on a picture source.
loading="lazy"
An img attribute that delays loading until the user scrolls near the image; never use it on the main image at the top.

Recap

  • img { max-width: 100%; height: auto; } plus width and height attributes stop overflow and layout shift.
  • srcset and sizes handle resolution switching; picture handles formats and art direction.
  • loading="lazy" belongs below the fold only, never on the hero.
  • alt always goes on the img, not on picture or source.
Also in this lesson: