Responsive Images

HTML · Lesson 17 of 44 8 min read Updated

A visitor on a ₹9,000 phone with a slow connection and a visitor on a large laptop screen should not download the same image. The phone needs a smaller file that loads quickly; the laptop needs a bigger, sharper one. Responsive images are the HTML features that let each device get a suitable image.

This lesson builds on HTML Images. You will learn to make images shrink to fit, to offer several sizes of one image with srcset and sizes, and to use <picture> to change the crop or the file format.

Step 1: let images shrink with CSS

By default an image is shown at its real size. An 800-pixel-wide image on a 360-pixel phone screen spills off the side and forces sideways scrolling. One CSS rule fixes this for every image on your site:

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Flexible image</title>
  <style>
    img { max-width: 100%; height: auto; }
    .card { width: 300px; border: 1px solid #ccc; padding: 8px; }
  </style>
</head>
<body>
  <div class="card">
    <img src="https://course.ethicscomputer.in/assets/samples/landscape.svg" alt="Hills and a river at sunrise" width="800" height="500">
    <p>The image is 800 pixels wide, but it fits this 300-pixel card.</p>
  </div>
</body>
</html>

max-width: 100% stops the image from growing wider than its container, and height: auto keeps its shape. Because the width and height attributes are still there, the browser still reserves the right space while loading.

This makes the image look right on a phone, but the phone still downloads the full 800-pixel file. The next step fixes that.

Step 2: offer several sizes with srcset and sizes

The srcset attribute lists several files of the same picture at different widths. The sizes attribute tells the browser how wide the image will be shown on the page. The browser then picks the smallest file that will still look sharp.

HTML
<img
  src="https://course.ethicscomputer.in/assets/samples/landscape.svg"
  srcset="https://course.ethicscomputer.in/assets/samples/landscape-400.svg 400w,
          https://course.ethicscomputer.in/assets/samples/landscape.svg 800w"
  sizes="(max-width: 600px) 100vw, 50vw"
  alt="Hills and a river at sunrise"
  width="800" height="500">

Read it like this:

  • srcset: "There is a 400-pixel-wide file and an 800-pixel-wide file." The w after each number is a width descriptor: the real width of that file in pixels.
  • sizes: "On screens up to 600 pixels wide, the image fills the whole viewport width (100vw). On bigger screens, it fills half (50vw)." The browser uses the first condition that matches.
  • src: the fallback file for very old browsers.

The browser also considers the pixel density of the screen. Many phones pack two or three device pixels into each CSS pixel to make text crisp. A 360-pixel-wide phone with a density of 3 needs about 1,080 real pixels to look sharp, so it may choose the larger file even though the screen is small. That is the browser doing its job; you only describe the options.

This example shows which file your browser picked. Try it on a phone and on a laptop:

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>srcset and sizes</title>
  <style>
    img { max-width: 100%; height: auto; }
  </style>
</head>
<body>
  <img id="photo"
    src="https://course.ethicscomputer.in/assets/samples/landscape.svg"
    srcset="https://course.ethicscomputer.in/assets/samples/landscape-400.svg 400w, https://course.ethicscomputer.in/assets/samples/landscape.svg 800w"
    sizes="(max-width: 600px) 100vw, 50vw"
    alt="Hills and a river at sunrise"
    width="800" height="500">
  <p id="report">Loading...</p>
  <script>
    const photo = document.querySelector("#photo");
    const report = document.querySelector("#report");
    function showFile() {
      report.textContent = `Your browser chose: ${photo.currentSrc.split("/").pop()}`;
    }
    if (photo.complete) {
      showFile();
    } else {
      photo.addEventListener("load", showFile);
    }
  </script>
</body>
</html>

currentSrc holds the address of the file the browser actually chose. Note that once a browser has the larger file, it may keep using it when the window gets narrower, because it already has a sharp image.

Fixed-size images and x descriptors

Some images are always shown at the same size, such as a logo in the header. For these, you only care about pixel density. Use x descriptors instead of w, and leave out sizes:

HTML
<img
  src="https://course.ethicscomputer.in/assets/samples/landscape-400.svg"
  srcset="https://course.ethicscomputer.in/assets/samples/landscape-400.svg 1x, https://course.ethicscomputer.in/assets/samples/landscape.svg 2x"
  alt="Hills and a river at sunrise"
  width="400" height="250">

Here the image is always 400 CSS pixels wide. Normal screens get the 400-pixel file (1x) and high-density screens get the 800-pixel file (2x).

Step 3: change the crop with picture

Sometimes a smaller version of the same image is not enough. A wide landscape photo becomes a thin strip on a phone, and the important part is too small to see. A taller crop would work better. Choosing a different crop for different screens is called art direction, and it needs the <picture> element.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Art direction</title>
  <style>
    img { max-width: 100%; height: auto; }
  </style>
</head>
<body>
  <h1>Visit Jodhpur</h1>
  <picture>
    <source media="(max-width: 500px)" srcset="https://course.ethicscomputer.in/assets/samples/portrait.svg" width="400" height="600">
    <img src="https://course.ethicscomputer.in/assets/samples/landscape.svg" alt="Jodhpur at sunrise, with the old clock tower and the hills around the city" width="800" height="500">
  </picture>
  <p>Make the preview narrower than 500 pixels to see the tall version.</p>
</body>
</html>

How <picture> works:

  • It contains zero or more <source> elements and one <img> at the end. The <img> is required: it is the element that is actually shown, and it holds the alt text.
  • The browser checks the <source> elements in order and uses the first one whose media condition matches. If none match, it uses the <img>.
  • Each <source> can have its own width and height, because each crop has its own shape.

Unlike srcset alone, a media condition is a rule, not a hint. The browser must follow it, so the image changes when you resize the window.

Offering modern formats

<picture> is also how you offer newer, smaller formats such as AVIF and WebP while keeping a safe fallback. The type attribute tells the browser the format, and it skips any it cannot display without downloading them:

HTML
<picture>
  <source type="image/avif" srcset="images/town-hall.avif">
  <source type="image/webp" srcset="images/town-hall.webp">
  <img src="images/town-hall.jpg" alt="The old town hall in Lucknow at sunset" width="1200" height="800">
</picture>

All current browsers can show AVIF and WebP, but this pattern still matters for older devices, and it costs nothing.

Which tool to use

SituationUse
Every image, alwaysCSS max-width: 100% and height: auto
Same picture, shown at different widthssrcset with w descriptors and sizes
Same picture, always the same sizesrcset with x descriptors
Different crop on small screens<picture> with <source media>
Newer formats with a fallback<picture> with <source type>

Common mistakes

  • Using w descriptors without sizes. The browser then assumes the image fills the full viewport width and often downloads a bigger file than needed.
  • Putting alt on <source>. Only the <img> has alt, and it is used whichever file is chosen.
  • Forgetting the <img> inside <picture>. Without it, nothing is shown.
  • Putting the general <source> first. The first match wins, so list the most specific conditions first.
  • Listing a file with the wrong width. The number before w must be the file's real pixel width.

Key points

  • Start with CSS max-width: 100% and height: auto so images fit any container.
  • srcset with w descriptors lists sizes of one picture; sizes says how wide it will be shown.
  • The browser picks a file based on display width and pixel density; you only describe the options.
  • Use x descriptors for images that are always the same size.
  • <picture> with <source media> changes the crop; <source type> offers AVIF and WebP with a fallback.
  • The <img> inside <picture> is required and carries the alt text.

Exercise

Write the HTML for a hero image on a travel page. On screens up to 500 pixels wide, show {{samples}}/portrait.svg (400 by 600). On wider screens, show the landscape image, offering both {{samples}}/landscape-400.svg (400 pixels wide) and {{samples}}/landscape.svg (800 pixels wide), and tell the browser the image fills the full viewport width. Write good alt text and set the sizes.

Show solution
HTML
<picture>
  <source media="(max-width: 500px)" srcset="https://course.ethicscomputer.in/assets/samples/portrait.svg" width="400" height="600">
  <img
    src="https://course.ethicscomputer.in/assets/samples/landscape.svg"
    srcset="https://course.ethicscomputer.in/assets/samples/landscape-400.svg 400w, https://course.ethicscomputer.in/assets/samples/landscape.svg 800w"
    sizes="100vw"
    alt="Jodhpur at sunrise, with the old clock tower and the hills around the city"
    width="800" height="500">
</picture>

The <source> handles the narrow-screen crop. On wider screens the <img> itself uses srcset and sizes, so the browser can still choose between the two landscape files. The alt text sits on the <img>.

Quick Quiz

1. What does 800w mean in a srcset?

2. Which element must always be inside <picture>?

3. You want a taller crop of a photo on phones. What do you use?

4. Why might a small phone download the larger image from a srcset?

Learn HTML with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call