Better Responsive Images With the picture Element

This article will introduce you to <picture>, a new proposed element created to try and solve the problem of serving the version of content images which better suits the device currently visiting a web page.

Why Do We Need a New Element?

Responsive Web Design (RWD) has taken web developers and designers by storm, changing the way they approach the development of a website. When talking about RWD, I love to make an analogy. We, as people involved in software development, are always excited by new tools in the same way a child is thrilled by a new toy (you've heard of the recent diatribe on front-end automation tools, haven't you?). We are so intrigued by new toys that sometimes we use, and even develop, tools that don't resolve a real issue. Well, RWD isn't like a new toy that everybody loves to play with, without a good reason. It's a methodology that helps us solve real problems: adapting a website for a great variety of screens. However, as many (all?) things in life, it isn't perfect and has some limitations.

One of the most important open issues is serving content images for an almost infinite range of devices, trying to serve the version that better suits the specific device currently visiting our website. For those of you who don't know what content images are, they are the images part of the content. Therefore, they should be shown using the <img> tag and not a CSS rule such as background-image. So far, three main proposals were made, discussed, rejected, and even resurrected (as the picture element). The proposals are: the srcset attribute, the picture element, and the src-n attribute. All of them tried to cover the wider range of use cases possible but, unfortunately for us, none of them have been completely welcomed by all the actors involved. At the time of this writing, it seems that <picture> will be the way to go due to the positive comments on the revamped proposal by representatives of the main browsers. What I mean by revamped, is that the original proposal has been updated incorporating some features of the src-n attribute proposal.

Considering that based on the latest statistics of HTTPArchive.org, images constitute about the 62% of the total weight of web page, you can easily understand that solving the problem of content images is a primary issue, and the sooner we arrive to a solution, the better. In fact, an improvement in how and what images are served will lead to faster loading of websites, which in turn will lead to an improvement of the experience of the websites' users.

Important Note

Before going ahead, I want to stress that this is still a proposal, hence the specifications are in a state of flux, and nobody can assure you that <picture> will reach the final stage. In addition, being a proposal at an early stage, no browsers offer support for it. For this reason, I strongly suggest you to follow this discussion, read the specifications from time to time, and wait until this proposal reaches a more stable state.

What's the <picture> Element?

Citing the specifications, "the picture element is intended to give authors a way to control which image resource a user agent presents to a user, based on media query and/or support for a particular image format". It, "should be used when an image source exists in multiple densities, or when a responsive design dictates a somewhat different image on some types of screens ("art direction")".

The proposed element is made of several pieces that we're going to analyze in detail. The first fact you need to know is that it's nothing but a container for other elements where we'll actually specify the different versions of the image we want to show. Inside a picture element you can find two tags: <source> and <img>. The latter is used to provide backward compatibility for older browsers or, in general, for browsers who don't support it. The source element has three attributes available:

srcset: Here is where we specify the URL of the image we want to show. The attribute allows for multiple URLs separated by a comma. In addition, taking cue from the srcset attribute proposal, we can pair each URL with a screen resolution or a width (considered as a min-width rule) specification. The latter is separated from the URL by a space.

media: Here we write a media query that, if evaluated to true, will suggest to the UA to show the image specified in the srcset attribute.

sizes: The attribute where we specify the set of intrinsic sizes for the sources described in the srcset attribute. It accepts multiple sizes separated by a comma.

Until now, we've spent too much time talking and seen nothing concrete. Let's fix this by seeing some code!

The <picture> in Action

As our first example, let's say that we developed a website with a mobile-first approach. Now, we want to show a content image and render the image "mobile.png" by default, the image "tablet.png" if the user screen is at least 480px, and "desktop.png" if the user screen is at least 1024px. Because we're smart developers, we also want to render the image "tablet.png" for those browsers who don't understand the picture element. To achieve this goal, we have to write the following code:

In the code above, we've adopted pixels as the unit for the media queries, but you can use em as well if you prefer.

The first example shown was quite straightforward. Let's see how we can make it more sophisticated using the expressive power of the srcset attribute. For the sake of the example, imagine that in addition to the previous requirements we want to differentiate the images based on the resolution of the screen. The resultant code is listed below:

As you can see, for each <source> in the code, we've specified more than one URL into the srcset attribute. 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). In this case, the browsers will firstly search for the source element that best accommodates the user screen based on the media query specified (if any). Then, it'll look at the screen resolution and choose the best fit among the images specified in the srcset attribute.

As our last example, we'll see how we can employ the sizes attribute. Let's say that we want our image to cover all the width of the device (100% of the width), regardless of its actual size and pixel density. To achieve this goal, we can specify the size we want to cover and the size of each image in the srcset attribute as shown below:

In this case, the User Agent will automatically calculate the effective pixel density of the image and choose which one to download accordingly.

Browser Compatibility

None. "Hey Aurelio, what do you mean by none? I was already starting to update my website!" If you recognize yourself in this sentence, I'm sorry to disappoint you. As I said multiple times in this article, the picture element is still a proposal and in a very early stage. So, you have to wait for a while before having the chance to employ it. Not all is lost, though. Scott Jehl created a polyfill for this proposal called picturefill. The latter was developed several months ago but has been updated several times to accommodate the specifications. Currently, it isn't updated to the latest specifications, so its syntax is different than the one described in this article. However, you can still take a look at it and maybe make a Pull Request to help the project.

Conclusions

In this article we discussed the issue of serving content images suitable for the device currently visiting a website. Then, we delved into the specifications of the picture element, the proposal that seems to have succeeded in conciliating browser vendors, developers, and all the actors involved in the process. Unfortunately for us, it's in a very early stage, so we can't employ it in our next projects. Nonetheless, I'm confident that browser vendors will start to implement it soon. As a final note, I strongly encourage you to read and follow the specifications.