Serving the appropriate image to users based upon the particulars of their device and environment has always been a tricky problem. This problem was highlighted with the advent of responsive web design, the very nature of which is to serve a single code base to each and every device.
As an author, you cannot know or plan for every possible device that may visit your site now or in the future. Only a browser knows the particulars of the device using it (screen size and device capabilities for example) at the moment it serves up and renders the content.
Conversely only the author (you and I) know what versions of an image we have at our disposal. For example, we may have three versions of the same image. A small, medium, and large: each with increasing dimensions to cover off a host of screen size and density eventualities. The browser does not know this. We have to tell it.
To summarize the conundrum, we have halve of the solution in that we know what images we have, and the browser has the other halve of the solution in that the browser knows what device is visiting the site and what the most appropriate image dimensions and resolution would be.
How can we tell the browser what images we have at our disposal so that it may chose the most appropriate one for the user?
In the first few years of responsive web design, there was no specified way. Thankfully, now we have the Embedded Content specification: https://html.spec.whatwg.org/multipage/embedded-content.html.
The Embedded Content specification describes ways to deal with the simple resolution switching of images (to facilitate a user on a higher resolution screen receiving a higher resolution version of images) and 'art direction' situations, for when authors want users to see a totally different image, depending upon a number of device characteristics (think media queries).
Demonstrating responsive image examples is tricky. It's not possible to appreciate on a single screen the different images that could be loaded with a particular syntax or technique. Therefore, the examples that follow will be mainly code and you'll just have to trust me that's it's going to produce the result you need in supporting browsers.
Let's look at the two most common scenarios you likely need responsive images for. These are switching an image when a different resolution is needed, and changing an image entirely depending upon the available viewport space.
Let's suppose you have three versions of an image. They all look the same except one is a smaller size or resolution intended for smaller viewports, another caters for medium size viewports, and finally a larger version covers off every other viewport. Here is how we can let the browser know we have these three versions available.
<img src="scones_small.jpg" srcset="scones_medium.jpg 1.5x, scones_large.jpg 2x" alt="Scones taste amazing">
This is about as simple as things get with responsive images, so let's ensure that syntax makes perfect sense.
First of all, the src attribute, which you will already be familiar with, has a dual role here; it's specifying the small 1x version of the image and it also acts as a fallback image if the browser doesn't support the srcset attribute. That's why we are using it for the small image. This way, older browsers that will ignore the srcset information will get the smallest and best performing image possible.
For browsers that understand srcset, with that attribute, we provide a comma-separated list of images that the browser can choose from. After the image name (such as scones_medium.jpg) we issue a simple resolution hint. In this example 1.5x and 2x have been used but any integer would be valid. For example, 3x or 4x would work too (providing you can find a suitably high resolution screen).
However, there is an issue here; a device with a 1440px wide, 1x screen will get the same image as a 480px wide, 3x screen. That may or may not be the desired effect.
Let's consider another situation. In a responsive web design, it wouldn't be uncommon for an image to be the full viewport width on smaller viewports, but only half the width of the viewport at larger sizes. The main example in Chapter 1, The Essentials of Responsive Web Design, was a typical example of this. Here's how we can communicate these intentions to the browser:
<img srcset="scones-small.jpg 450w, scones-medium.jpg 900w" sizes="(min-width: 17em) 100vw, (min-width: 40em) 50vw" src="scones-small.jpg" alt="Scones">
Inside the image tag we are utilizing srcset again. However, this time, after specifying the images we are adding a value with a w suffix. This tells the browser how wide the image is. In our example we have a 450px wide image (called scones-small.jpg) and a 900px wide image (called scones-medium.jpg). It's important to note this w suffixed value isn't a 'real' size. It's merely an indication to the browser, roughly equivalent to the width in 'CSS pixels'.
What exactly defines a pixel in CSS? I wondered that myself. Then I found the explanation at http://www.w3.org/TR/css3-values/ and wished I hadn't wondered.
This w suffixed value makes more sense when we factor in the sizes attribute. The sizes attribute allows us to communicate the intentions for our images to the browser. In our preceding example, the first value is equivalent to, "for devices that are at least 17em wide, I intend the image to be shown around 100vw wide".
If some of the units used, such as vh (where 1vh is equal to 1% of the viewport height) and vw (where 1vw is equal to 1% of the viewport width) don't make sense, be sure to read Chapter 5, CSS3 – Selectors, Typography, Color Modes, and New Features.
The second part is effectively, "Hi browser, for devices that are at least 40em wide, I only intend the image to be shown at 50vw". That may seem a little redundant until you factor in DPI (or DPR for Device Pixel Ratio). For example, on a 320px wide device with a 2x resolution (effectively requiring a 640px wide image if shown at full width) the browser might decide the 900px wide image is actually a better match as it's the first option it has for an image that would be big enough to fulfill the required size.
An important thing to remember is that the sizes attributes are merely hints to the browser. That doesn't necessarily ensure that the browser will always obey. This is a good thing. Trust me, it really is. It means that in future, if there is a reliable way for browsers to ascertain network conditions, it may choose to serve one image over another because it knows things at that point that we can't possibly know at this point as the author. Perhaps a user has a setting on their device to 'only download 1x images' or 'only download 2x images'; in these scenarios the browser can make the best call.
The alternative to the browser deciding is to use the picture element. Using this element ensures that the browser serves up the exact image you asked for. Let's take a look at how it works.
The final scenario you may find yourself in is one in which you have different images that are applicable at different viewport sizes. For example, consider our cake based example again from Chapter 1, The Essentials of Responsive Web Design. Maybe on the smallest screens we would like a close up of the scone with a generous helping of jam and cream on top. For larger screens, perhaps we have a wider image we would like to use. Perhaps it's a wide shot of a table loaded up with all manner of cakes. Finally, for larger viewports still, perhaps we want to see the exterior of a cake shop on a village street with people sat outside eating cakes and drinking tea (I know, sounds like nirvana, right?). We need three different images that are most appropriate at different viewport ranges. Here is how we could solve this with picture:
<picture>
<source media="(min-width: 30em)" srcset="cake-table.jpg">
<source media="(min-width: 60em)" srcset="cake-shop.jpg">
<img src="scones.jpg" alt="One way or another, you WILL get cake.">
</picture>First of all, be aware that when you use the picture element, it is merely a wrapper to facilitate other images making their way to the img tag within. If you want to style the images in any way, it's the img that should get your attention.
Secondly, the srcset attribute here works exactly the same as the previous example.
Thirdly, the img tag provides your fallback image and also the image that will be displayed if a browser understands picture but none of the media definitions match. Just to be crystal clear; do not omit the img tag from within a picture element or things won't end well.
The key difference with picture is that we have a source tag. Here we can use media query style expressions to explicitly tell the browser which asset to use in a matching situation. For example, our first one in the preceding example is telling the browser, "Hey you, if the screen is at least 30em wide, load in the cake-table.jpg image instead". As long as conditions match, the browser will dutifully obey.
As a bonus, picture also facilitates us providing alternate formats of an image. 'WebP' (more info at https://developers.google.com/speed/webp/) is a newer format that plenty of browsers lack support for (http://caniuse.com/). For those that do, we can offer a file in that format and a more common format for those that don't:
<picture>
<source type="image/webp" srcset="scones-baby-yeah.webp">
<img src="scones-baby-yeah.jpg" alt="Again, you WILL eat cake.">
</picture>Hopefully this is now a little more straightforward. Instead of the media attribute, we are using type (we will do more with the type attribute in Chapter 4, HTML5 for Responsive Web Designs), which, although more typically used to specify video sources (possible video source types can be found at https://html.spec.whatwg.org/multipage/embedded-content.html), allows us here to define WebP as the preferred image format. If the browser can display it, it will, otherwise it will grab the default one in the img tag.
There are plenty of older browsers that will never be able to make use of the official W3C responsive images. Unless there is a specific reason not to, my advice would be to allow the built-in fallback capabilities do their thing. Use a sensibly sized fallback image to provide them with a good experience and allow more capable devices to enjoy an enhanced experience.