HTML & CSS Tip of the Week

The picture element

Published on


Sometimes, designs have different images for large and small screen layouts. In those situations, it can be tempting to simply bring in multiple images and use a media query in your CSS to control when we see each one, like this:

.my-image-small-viewports {
  display: block;
}

.my-image-large-viewports {
  display: none;
}

@media (width > 780px) {
  .my-image-small-viewports {
    display: none;
  }
	
  .my-image-large-viewports {
    display: block;
  }
}

Luckily, there is a better way, thanks to the <picture> element!

The <picture> element is incredibly easy to use. To start with, you can just wrap your normal image inside of one!

<picture>
  <img src="/..." alt="">
</picture>

This will work fine, but is also a little useless. The <picture> element becomes more useful when we add a <source> inside of it, which allows for multiple sources if needed:

<picture>
  <source
    srcset="/image-medium-viewports.webp"
    media="(min-width: 600px)"
  >
  <source
    srcset="/image-large-viewports.webp"
    media="(min-width: 780px)"
  >

  <img src="/image-small-viewports.webp" alt="">
</picture>

When using the <picture> element, we must include an <img> inside of it. The source of the <img> will act as the default source, and the browser will replace that source with one of the others if the conditions from the media are met.

This is for when you need different images, not only different resolutions or sizes

Use the <picture> element for when you are doing art direction, such as loading in a different crop on an image based on the size or orientation of the viewport.

<picture>
  <source
    srcset="/image-cropped-short.webp"
    media="(orientation: portrait)"
  >

  <img src="/image-full-crop.webp" alt="">
</picture>

If all you want to do is load in a larger version of the same image for higher dpi devices or for when the viewport is larger, you can simply use the srcset directly on an image instead.

<img
  src="image-low-res.webp"
  srcset="image-medium-res.webp 2x, image-highres.webp 3x"
  alt=""
>

The 2x and 3x here are pixel density descriptors. The browser will choose the best image based on the rendered size of the image, viewport, and pixel density of the device.

Alternatively, you can also supply the browser with sizes:

<img
  src="image-low-res.webp"
  srcset="image-medium-res.webp 400w, image-highres.webp 800w"
  alt=""
>

The only limitation is you cannot mix and match the pixel density descriptions and sizes. Either use one or the other.

Dive deeper