150 Days of HTML

Chapter 30 | picture and source elements

In this chapter we start to dig into the embedded content elements. The elements we cover in this chapter are, picture, and source. The picture element and its related source element, introduced with HTML5, give us new powerful tools to improve the user experience from both a performance and visual perspective. So let’s dig into the details and see how you can use these new elements.

picture

The picture element is merely a container element and does not display anything by itself. It is a container for zero or more source elements and one img element. So what is the difference between using the picture element or merely using an img element by itself? With the img element you specify a single source image that is displayed no matter the user’s environment and support for the specific image format. There are of course ways to manipulate the source image through JavaScript, but what if the browser could do the heavy lifting for us based on its knowledge of the environment and user preferences?

That is then where the picture element comes in. Instead of just our single img element, we can specify multiple source images along with some hints to the browser about when to use which source.

source

As with picture the source element by itself does not represent anything. The source element can also be used with other elements such as the video and audio elements. Today we will focus on its use with the picture element. As hinted at above, we will use the source element to provide additional source options for the img element contained within the parent picture element. With that said, it is not the exclusive domain of the source element to enable multiple sources; this can also be achieved with just the img element. There are some differences though, that will guide your choice in using just the img element or using the picture element with source and img.

Attributes shared by the source and img elements are:

  • srcset
  • sizes
  • width
  • height

Technically they also share the src attribute, but it is only valid when source is used with either the video or audio element. The attributes unique to source are:

  • type
  • media

type

The type attribute allows you to specify the type of media asset you are referencing with the source element. Why is this useful?

It used to be that we had essentially two widely supported image formats on the web. Those being GIF(Graphics Interchange Format) and JPEG(Joint Photographics Experts Group). Later on, we also got support for the PNG(Portable Network Graphics) image format that is widely used on the web today.

Things have not stood still though and recently(roughly around 2018) Webp developed by Google was introduced. The latest addition to image formats on the web is AVIF with growing support across user agents.

With the type attribute we can take advantage of these new formats and offer users faster-loading pages but still provide fallbacks for those browsers that do not support the newer image formats.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<picture>
  <source srcset="trevor-gerzen-r_XS7sml57o-unsplash.avif" type="image/avif" />
  <source srcset="trevor-gerzen-r_XS7sml57o-unsplash.webp" type="image/webp" />
  <img
    src="trevor-gerzen-r_XS7sml57o-unsplash.png"
    width="1223"
    height="815"
    alt="A beautiful sunset in the background with two surfers paddling into the surf in the foreground"
  />
</picture>

Photo by Trevor Gerzen on Unsplash

When loading the below example in Chrome and looking in the network panel of the developer tools, you will see that Chrome loads the AVIF file format:

AVIF file format shown to load in Chrome devtools network panel

Opening the same example in Safari demonstrates how it falls back to WebP format:

WebP file format shown to load in Safari devtools network panel

As you will also see in the example, there is a significant difference in the file size of the various formats. As performance is a large part of the user experience and accessibility, this is a great tool to have in your arsenal.

  • AVIF - 171kb
  • Webp - 208kb
  • JPG - 236kb

Live Codepen - Using picture with multiple source elements and fallback

media

The other use case where you would choose picture over just img is when used with the media attribute. As with the link element, the media attribute can be used to specify a media query. The browser will then load the image whose media query most closely matches the current environment starting from the top and moving on until it reaches the img element.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<picture>
  <!-- The below image and dimensions will be used up to a max viewport width of ~320px -->
  <source
    srcset="https://placekitten.com/g/300/300"
    media="screen and (max-width: 20em)"
    width="300"
    height="300"
  />
  <!-- The below image and dimensions will be used up to a max viewport width of ~1024px -->
  <source
    srcset="https://placekitten.com/g/400/500"
    media="screen and (max-width: 64em)"
    width="400"
    height="500"
  />
  <!-- The below image and dimensions will be used for viewports larger than ~1024px -->
  <img
    src="https://placekitten.com/g/1080/720"
    width="1080"
    height="720"
    alt="A random cute kitten"
  />
</picture>

When you open the example below, also open up your browser’s developer tools and switch it to responsive mode(Chrome How-To - Firefox How-To). As you switch between small mobile (320px viewport size or smaller), tablet, and desktop, you will notice that differently sized images load. Not only are the images smaller on smaller viewports, but we also specify different aspect ratios. This is what is commonly known as art direction and is a common use case for the picture element.

See the live example on Codepen.io

Before we move on to the img element, you might be saying, “Hold on, you said the source element does not represent anything visually, but in the examples above, it does?”. Looking at the second example, what really happens is something like the following.

  1. The browser encounters the picture element and looks for its first child element.
  2. It finds the source element and starts to look at its attributes.
  3. When it encounters the media attribute, it parses its value. Seeing that what we specified is a valid media query string, it executes it against the current environment.
  4. Let’s assume it matched.
  5. It now looks for its child img element.
  6. It then replaces the src attribute value with the value from the source element that matched the environment. Seeing that we also specified width and height, it also copies over those values and renders the img element. And walla! 🎉 😀

That then covers the majority of the most important aspects of these elements. We will encounter the source element again when we look at the video and audio elements. In the next chapter we wil dig into the img element and oh boy, hold on to your hats, folks 😀

Buy me a coffee and support the work on 150 Days of HTML.