Improving Responsive Images with the Picture Element
A while ago I wrote an article about the srcset attribute. This is an attribute of the
img element designed to serve the right image to a specific device. The
srcset attribute allows developers to specify a list of sources for an image from which one will be chosen based on the pixel density or size of the user’s screen and displayed to the user.
The browser is provided with a set of “suggestions” about the correct behavior with certain types of images, thus improving the loading time of a page. This technique reduces the weight of a website for devices with small screens (that we tend to think of as devices with a slow connection), and so improves user experience. At the time of writing that article this attribute was a standalone proposal but has since been incorporated into a wider proposal, the
In this tutorial I’ll give an overview of the
picture element, describing its main features and advantages.
What’s the picture element?
The topic of providing the right image (in terms of size and pixel density) to a given device has been discussed extensively over the years. Examples of recent articles are “Responsive Images: If you’re just changing resolutions, use srcset.” by Chris Coyier and “Don’t use <picture> (most of the time)</picture>” by Jason Grigsby.
The first thing to understand about the
picture element is that it doesn’t display anything on its own. It simply provides a context for the images that are inserted into it and this enables browsers to choose from multiple source URLs. This element is different from other similar container elements like the well-known
src attribute has no meaning when the
source element is nested within a
picture and the resource selection algorithm is not the same.
This could be summarized as follows. For the
audio elements, if the
src attribute is specified, it has absolute priority on the
source elements, which are not considered. But in the case of the
picture element, since we’ve seen that it’s nothing more than a container, the
source element is the one that is considered in any situation.
If we return to the definition available in the W3C specifications, we discover that the picture element is a container which provides multiple sources to its contained
img element. This allows authors to declaratively control or give hints to the user agent about which image resource to use, based on the screen pixel density, viewport size, image format and other factors. It represents its children. Inside this element we can place two different tags,
<img />, used to provide backward compatibility for browsers that don’t support it, and
source element possesses four attributes:
srcset: Using this attribute we can specify the URL of the image that we want to show. This accepts multiple URLs separated by a comma. As with the
srcsetattribute, we have the possibility to pair each URL with a screen resolution or a width specification (separated from the URL by a space).
media: Here we write a media query that, if evaluated to true, will give suggestions about which image specified in the
srcsetattribute to show.
sizes: This is the attribute where we specify the set of intrinsic sizes for the sources described in the
srcsetattribute. It also accepts multiple sizes separated by a comma.
type: This gives the type of the images in the source set, to allow the user agent to skip to the next
sourceelement if it does not support the given type.
picture element can be used in various ways. Let’s look at a quick list of the “directions” you can give to this element:
Art direction-based selection: This is the most common use of the
picture element in responsive design. Instead of having one image scaled up or down based on viewport width, there are multiple images that can more appropriately fill the browser viewport. This is good because, as the W3C specifications suggest. “Using different images that have been cropped to fit a particular screen’s features can help in communicating a message effectively.”
Device-pixel-ratio-based selection: As designers, you should aim to display images in a way that reduces perceptible crops. Devices with different screen densities require images with different minimal resolutions. Thus, the higher the pixel density, the more pixels an image needs to look good.
Viewport-based selection: Authors might want to show the same image content but with different rendered sizes depending on the width of the viewport. This is usually referred to as “viewport-based selection”. Image dimensions in responsive layouts tend to vary according to the size of the viewport. It’s common for images with large dimensions to be sent to browsers with narrow viewports, which are then resized by the browser to fit the design. Ideally, you should serve images that match the user’s viewport dimensions, without sending more data to the user than you would otherwise need to.
Image format-based selection: Authors might want to show the same image content but using different image formats, depending on which image formats the user agent supports. This is usually referred to as “image format-based selection”. Designers should always try to provide the same image in multiple resolutions. In this way, high-res devices will get the optimum image for a given resolution, while low-resolution devices will avoid wasting time and bandwidth downloading overly-large (useless) files.
Using Picture: practical examples
Now that we’ve discovered the use cases of this element, it’s time show an example. Imagine that we are working on a website with a mobile-first approach. In this hypothetical website we’ll use the same images, called
Autumn in Moscow, that I’ve employed in the previous article. In the following code, we’ll show the image
autumn-in-moscow-mobile.png by default and then the images that we’d like to render if users are visiting the website with a tablet or from their desktop. Therefore,
autumn-in-moscow-tablet.png will be used for devices with a screen of at least 680px, with
autumn-in-moscow-desktop.png for devices with a screen width of at least 1024px. Because we can expect that there’ll be some browsers which will not be able to recognize the
picture element, we’ll also provide a fallback image. The fallback image used is
The code that implements the above is:
<picture> <source media="(min-width: 1024px)" srcset="autumn-in-moscow-desktop.png"> <source media="(min-width: 680px)" srcset="autumn-in-moscow-tablet.png"> <source srcset="autumn-in-moscow-mobile.png"> <img src="autumn-in-moscow.png" alt="Autumn in Moscow"> </picture>
So far, so good. But what if we want to improve the specificity of our snippet focusing on the power of the
srcset attribute? Think about stressing the difference of the images considering the resolution of the screen. The following code will give you an idea of what you’d have to add:
<picture> <source media="(min-width: 1024px)" srcset="autumn-in-moscow-desktop.png, autumn-in-moscow-desktop-hd.png 2x"> <source media="(min-width: 480px)" srcset="autumn-in-moscow-tablet.png, autumn-in-moscow-tablet-hd.png 2x"> <source srcset="autumn-in-moscow-mobile.png, autumn-in-moscow-mobile-hd.png 2x"> <img src="autumn-in-moscow.png" alt="Autumn in Moscow"> </picture>
As we’ve discussed in the previous section, the
srcset attribute accepts multiple URLs separated by a comma. Also, we can match each URL with a screen resolution or a width specification. In this case, the second URL is paired with the string 2x, separated by a space, that targets users with a high-resolution display (pixel density 2x, like the Retina).
The first request that the browsers undertakes is the
source element that best accommodates the user screen based on the media query specified (if present). The second element taken into consideration will be the screen resolution, with the choice of the best fit image among those which have been specified in the
To complete our overview of the elements that compose the
picture element, let’s have a look at how we can use the
sizes attribute. Let’s imagine we want our image to cover 50% of the width, regardless of its actual size and pixel density. To achieve this goal, we have to specify the size we want to cover and the size of each image in the
srcset attribute as follows:
<picture> <source sizes="50vw" srcset="autumn-in-moscow-mobile.png 480w, autumn-in-moscow-small-tablet.png 768w, autumn-in-moscow-tablet.png 968w, autumn-in-moscow-desktop.png 1024w"> <img src="autumn-in-moscow.png" alt="Autumn in Moscow"> </picture>
picture element is currently only supported by default (meaning without the need to activate any flag in your browser) in Chrome 38+ and Opera 25+. Since version 34, Firefox supports this element behind a flag. Starting from version 38, Firefox will support
picture by default too. The element is still under consideration in Internet Explorer. Luckily, Scott Jehl created a polyfill for this proposal, called picturefill, updated to the latest specifications. You can download it and find all the information you may need here.
In this article we delved into the specifications of the
picture element as a solution to deal with the problem of responsive images. It allows developers to solve the issue of setting the right image resolution for multiple devices. As we’ve seen this is the latest solution that after many years of discussion and it’s made of the best of all the other proposals of the past years. I recommend you to read the specifications to understand even more the great potential and use cases of this element.