Modern responsive techniques: srcset attribute vs picture element

Posted in: HTML

Dec 5, 2015

As the year draws to a close many of the major web development and design publications publish their 2016 prediction lists. This year many of these publications share the same predicted trends in web development / design, stating that there will likely be a larger emphasis on things like big data, cinemagraphs, full page video, material design and more. Another common candidate is the rise of more natively implemented responsive design. 

Whilst we already do implement responsive design in just about everything, things like CSS flexbox means that the code behind the layout can be simplified dramatically as we push more responsibility to the browser. In the same idea of this is the continued rise and standardisation of srcset and the picture element. Srcset and isn't exactly new, and have been discussed pretty widely, but on the back of these aforementioned lists I figured it would be a good opportunity to use a refresher, and delve into the actual differences since that aspect is seemingly overlooked quite often. 

Srcset

The srcset attribute is an attribute that we can attach to a regular image element. It allows us to specify describe different images based on their resolution or size, so the browser can best determine which image is suited for a given situation. 

The obvious advantage of doing this is that a user only has to download the image that is most suitable to their device;  i.e., if they are on a a high resolution device, serve the high resolution image, or if they are on a device with a small viewport, give them the image that best fits that. 

Adding srcset is achieved like so:

<img alt="something or rather" src="lowres.jpg" srcset="highres.jpg 2x" />

In this example a device with a pixel density of 2x will load the image defined in the srcset attribute, whereas one that doesn't will just use the regular src attribute. It's actually the 'x' descriptor that I'm appending to a numerical value (2 in this case) that is specifying the pixel density. It should also be mentioned that browser which don't recognise srcset will gracefully degrade to using the src attribute as per usual. 

As mention earlier, resolution / pixel density is not the only definition you can serve to the srcset attribute. You can also pass a descriptor to the image's size as well. To do this, specify a pixel value and add a 'w' (for width). You can even describe multiple images by using a comma separated list:

<img alt="a highly imaginative alt tag" srcset="small-size.jpg 420w, big-size.jpg 960w" />

With the above example, the browser will look at the size of the images (by way of their described widths) and then determine which image is best suited based on the browser's current viewport width. So... nice and native, just the way we like it. 

Srcset also pairs well with another new attribute called sizes. Sizes specifies how large the image should be rendered relative to the viewport of the browser. For example:

<img alt="another amazing alt tag to dazzle you all" 
    sizes="(max-width:400px) 100vw, 50vw" 
    srcset="small-size.jpg 420w, big-size.jpg 960w" 
/>

Now the browser will use either 100vw or 50vw (rendering a full width image or a half width image respectively) depending on the width of the viewport itself. If the width is greater than 400px, then the image will be rendered half of the width of the viewport, otherwise the full width. Remember, the 'w' descriptor isn't necessarily the size the image will actually render as, it's just describing to the browser how large the image is, the sizes attribute will specify a size for an actual render. 

So far what we've covered should solve some common problems. First, handling high pixel density devices is done using the 'x' descriptor which is useful for swapping out images that have different resolutions but the same size. Secondly, changing the width / height of an image in relation to the viewport width is achieved by the 'w' descriptor and media queries defined in the sizes attribute. 

However, there are still some other use cases to address, such as loading an entirely different image with a different or altered subject matter (think a change in art direction). Sure we could technically achieve this by srcset alone, but it's not the intention of the specification and is a bit of a hack. We might also want to load in different file formats and give the browser the option to use the most efficient one it can first. So how to address these concerns? Enter stage left, the picture element. 

The picture element has a syntax that might seem familiar to those who have used the audio or video elements in HTML5. Like those, the picture element itself is just a container which wraps a number of child source elements. On these source elements we will need to attach a media attribute and for its value specify a media query. In addition to media attributes, source elements will also support sizes, our friend srcset and type attributes. Let's take a look at a basic example:

<picture>
    <source media="min-width:400px" srcset="large.jpg" />
    <source media="min-width:300px" srcset="small.jpg" />
    <img alt="Did you expect my alt tags to get better?" src="fallback.jpg" />
</picture>

So in the above example I've supplied to source elements, and an image element. At least one image element is required for every time  is used and will act as a fallback for browsers that do not support the picture element. The two source elements each have a media attribute which, like a CSS media query, instructs the browser on what to display if they evaluate to true. In this case the browser will be forced to render the first source element if its width is larger than or equal to 400px and the second source element if is is larger than or equal to 300px. It's this media attribute and query value that gives the picture element the subtle yet important distinction from just a regular with srcset. With we get to instruct the browser which source element to use and subsequently which image to load. With a image element using srcset, the browser gets to choose what to load itself based on its own calculations on what is the most suitable with the information we provide via sizes, and the 'w' and 'x' descriptors. 

That being said, you likely will be notice that we don't specify src on a source element (this is getting silly now) rather it uses srcset. So we can actually apply the same techniques from our earlier examples on the picture element. Like so:

<picture>
    <source media="max-width:500px" 
        sizes="(max-width:320px) 100vw, 50vw" 
        srcset="dog-small.jpg 320w, dog-large.jpg 500w" 
    />
    <source media="max-width:960px"
        sizes="(max-width:700px) 100vw, 50vw"
        srcset="cat-small.jpg 700w, cat-large.jpg 960w"
    />
    <img alt="Another witty alt tag." src="animals.jpg" />
</picture>

Now we can force the browser to use a source element, but then give it the choice to use one of the images described in the srcset attribute. It's a contrived example somewhat, but valid. You'll also notice that I've switched the entire subject of the image between the two source elements. An image of a dog for a larger display and a cat for the smaller. So although this is yet again contrived and not something you would use in a real world scenario, it demonstrates one of the reasons for using the picture element over an image with srcset. That reason is, the art direction switch. 

Whereas with an image element and srcset you will usually find yourself serving essentially the same picture but at different sizes and resolutions, you might at times be forced to change the art entirely in some cases (there might be text on the image that needs to be re-worded / removed at smaller resolutions, or the dimensions need to be cropped considerably and so much the subject needs to change). In this case we use , since it semantically makes more sense than trying to switch in different images in an image element with srcset and more is aligned with its intention. 

A final feature worth mentioning for picture elements is the use of type selection. This is where we have the opportunity to try and serve some less standardised but more efficient image formats for the browser, and allow the browser to move through each in turn until it finds one it can use: 

<picture>
    <source type="image/bpg" src="somebpg.bpg" />
    <source type="image/svg" src="somesvg.svg" />
    <img alt="well, this is the best I could do" src="somejpg.jpg" />
</picture>

So which to use?

Hopefully you can see by now that picture and srcset shouldn't just be used interchangeably, if you're using for everything than it's like there are some cases when a simple image element with a srcset attribute will suffice. There's no better argument for this than by just looking at browser support. Currently srcset is supported by all the latest iterations of the major browsers except for IE. is slightly behind that in terms of support with both Safari and IE lacking the ability to use it. There are of course polyfills available, but is it worth that extra code if you aren't using the picture element for art direction switch use cases or type switch use cases?

Though with luck, polyfills should hopefully not be needed as we move into 2016 and browser support for these specifications continues to grow. By giving the browser more responsibility in our responsive designs, we can create a more seamless experience for everyone, no matter their device. 

That's certainly a 2016 I'm looking forward to. 

Happy coding.