Illustration by

Using Responsive Images (Now)

Ever since Ethan Marcotte started talking about responsive web design in 2010, developers and designers have been scrambling to find ways to deal with the issue of responsive images. It’s a thorny problem because we’re serving the same website, with the same image sources, across a wide range of device widths. Do you want a blurry, pixelated image on a large display? Or do you want to load a huge (but oh-so-pretty) image on your mobile phone? Talk about being stuck between a rock and a hard place.

Article Continues Below

Loads of smart people, namely the Responsive Issues Community Group (RICG), have been working together to solve this conundrum. That’s why the picture element and the srcset and sizes attributes are being drafted into the HTML 5.1 specification. Because we cannot predict where and how users are going to view our websites, we need the browsers themselves to pick the best image for the situation. The new specification will address the following issues:

  • Device-pixel-ratio-based selection
  • Viewport-based selection
  • Art direction-based selection
  • Image format-based selection

The spec also introduces two new attributes—srcset and sizes—to the img element. srcset lets us declare a set of image sources, which browsers will serve according to certain conditions we specify using descriptors. x descriptors indicate the pixel-density of the images, while w descriptors indicate the width of the images; the browser will use this information to pick the appropriate image from the list. The sizes attribute provides the browser with some context on the size of the image element to be displayed, and must be included when using srcset with w descriptors. This is especially relevant for variable-width images, which I’ll discuss in detail later.

The point is, we now have the option of serving images of different quality or art direction depending on the user’s viewport, without some complicated server-side setup. Responsive images will become part and parcel of the HTML specification; eventually, all browsers will support this solution.

Now, let’s take a tour of the selection types and how you can make them work for you.

Fixed-width images: device-pixel-ratio-based selection#section1

With the introduction of Retina screens, it became necessary to take into account not only screen resolution but also pixel density. Retina screens, 4K displays, UltraHD—all of these have way more pixels packed into them than a standard resolution display of the same size. More pixels = sharper image quality.

If, for some reason, you have an image that will always display at a certain width regardless of screen size—the site logo or a profile image, say—then device-pixel-ratio-based selection is the way to go. The browser will choose which image to load based on its device-pixel ratio.

The srcset attribute basically lists the pool of source images from which the browser can pick to load. It’s a comma-separated list. The x descriptor indicates the device-pixel ratio of the image. Depending on what environment the browser is operating in, it will utilize this information to select the appropriate image. Any browsers that don’t understand srcset will simply load the image declared in the src attribute.

<img srcset="crest-383.jpg 1.5x, crest-510.jpg 2x" src="crest-255.jpg" alt="USWNT crest" />
USWNT crest

An example of a fixed-width image might be a site’s logo, which remains the same size regardless of viewport width. Content-related images, however, are usually responsive; their sizes tend to change depending on the viewport. For those types of images, there’s a better method.

Fluid-width images: viewport-based selection#section2

For fluid-width images, we use srcset with the w descriptor and sizes. The w descriptor tells the browser the width of each image in the list. The sizes attribute is also a comma-separated list containing two values. As of the latest specification, if the srcset has any images using the w descriptor, then the sizes attribute must be present as well.

There are two values in the sizes attribute. The first is a media condition. The second is the source-size-value, which determines the width of the image given that particular media condition. One important thing to note is that you can’t use percentages as the source-size-value; the only relative CSS length you can use is vw.

<img srcset="uswnt-480.jpg 480w, 
             uswnt-640.jpg 640w, 
             uswnt-960.jpg 960w,
             uswnt-1280.jpg 1280w" 
     sizes="(max-width: 400px) 100vw, 
            (max-width: 960px) 75vw, 
            640px" 
     src="uswnt-640.jpg" alt="USWNT World Cup victory">
USWNT World Cup victory

Here, I’m telling the browser that for viewport widths up to 400 pixels, make the image 100% of the viewport width. At viewport widths up to 960 pixels, make the image 75% of the viewport width. And for everything above 960 pixels, make the image 640 pixels. If you’re unfamiliar with vw, take a look at Tim Severien’s great article explaining viewport units.

The browser utilizes the information from srcset and sizes to serve the image that best matches the stated conditions. If my browser’s viewport is 600 pixels, it would most likely display the image at 75vw. The browser will try to load the first image larger than 450 pixels, which is uswnt-480.jpg. If I’m on a Retina display with a device-pixel ratio of 2, then the browser will try to load the first image larger than 900 pixels, which should be uswnt-960.jpg. We can’t be certain of exactly which image will be served because each browser has some leeway in how their algorithm picks an appropriate image based on the information we provide. This is what “viewport-based selection” means.

Because the first two examples display the same image at different quality levels, the srcset attribute alone is sufficient. Again, if you’re worried about legacy browsers, that’s what the src is for—those browsers will just treat it as a regular image and load from src. If you want to show slightly different images at different widths, for example, showing only the critical parts of an image at smaller widths, then use the picture element.

picture: art direction-based selection#section3

The picture element is like a wrapper for the image and its sources. Browsers still need img to recognize that an image needs to be served; without img, nothing will render at all. source provides the browser alternate versions of the image to display. Art direction-based selection is used for situations when we want a specific image to display at a specific breakpoint. There is no ambiguity in terms of image selection when you use the picture element.

<picture>
  <source media="(min-width: 960px)" srcset="ticker-tape-large.jpg">
  <source media="(min-width: 575px)" srcset="ticker-tape-medium.jpg">
  <img src="ticker-tape-small.jpg" alt="USWNT ticker-tape parade">
</picture>
USWNT ticker-tape parade

In this example, when the viewport is larger than 960 pixels, a landscape-oriented version of the image (ticker-tape-large.jpg) is loaded. For widths larger than 575 pixels, the browser loads a cropped portrait-oriented image (ticker-tape-medium.jpg) instead. And for widths smaller than 575 pixels, the image (ticker-tape-small.jpg) loaded has been cropped to focus just on one player.

The picture element is backwards compatible; browsers that don’t support the picture element will display img as usual. All standard attributes for images, like alt, should be applied to img, not picture.

source: image format-based selection#section4

A number of new image formats have come into existence in recent years. These new image formats offer better quality at lower file sizes. Sounds good, right? Until you realize that none of these formats is universally supported across all browsers. Google’s WebP performs very well, but is only natively supported by Chrome and Opera. JPEG-XR, originally known as HD Photo, was a proprietary image format released by Microsoft, supported only by Internet Explorer. If you want to learn more, Zoltan Hawryluk wrote an in-depth examination of these new formats.

<picture>
  <source type="image/vnd.ms-photo" src="wwc2015.jxr">
  <source type="image/jp2" src="wwc2015.jp2">
  <source type="image/webp" src="wwc2015.webp">
  <img src="wwc2015.png" alt="WWC 2015">
</picture>

Because source also has a type attribute, by specifying the MIME type of each image, browsers can choose the first source that has a type attribute of a supported MIME type. The order of the source matters, in this case, but if the browser doesn’t recognize any of the image types, it will just fall back to the original img element.

Can I use all this right now?#section5

At time of writing, picture is supported by the latest stable releases of Firefox, Chrome, and Opera. Safari and Internet Explorer do not support picture natively at all. srcset fares slightly better, with full support on the latest stable releases of Firefox, Chrome, and Opera, and partial support on Safari 8 and Internet Explorer Edge, where they allow for use of the x descriptors for resolution switching, but not the w descriptors.

Quite a few polyfills out there address this support problem. The most well-known is probably Scott Jehl’s picturefill. I currently use Alexander Farkas’s respimage on my own site. We’ve finally reached a point where we’ve agreed on a solution for how to deal with responsive images, and that solution is getting implemented across all major browsers. Even though the specification is still being refined, we’re really close to a native responsive solution.

And if you want to stay up-to-the-minute current, I highly recommend checking out the Responsive Issues Community Group. You can also sign up for their newsletter or follow them on Twitter.

About the Author

Chen Hui Jing

Chen Hui Jing is a self-taught designer and developer from Singapore. Reducing lines of code in her web projects makes her extremely happy. She used to play basketball full-time and launched her web career during downtime between training sessions.

33 Reader Comments

  1. Hi Terry,
    Your implementation is pretty interesting. Though it seems like every image will need to have an individual style applied to it? I’m not sure if the syntax validates either.
    There are quite a lot of varying opinions on picture, but I think the benefit is that it is a native HTML element that allows you to serve responsive images purely through mark-up.
    But thanks for sharing your technique.

  2. Great article! But I’m surprised it doesn’t mention the fallback-image double download problem. Briefly: Some browsers that understand <picture> and srcset/sizes will still download the fallback images because of “looking ahead” in the DOM. And other browsers that only understand that syntax with the use of a polyfill will also download the fallback image.

    Dave Newton wrote a really thorough walk-through (including addressing accessibility) from a couple of years ago. Even though that’s somewhat dated, the issue still exists. Picturefill.js omits the fallback src for this reason (the only fallback is the alt text). Drupal 8, which uses Picturefill, is (likely) going to omit it too.

    The drawback to omitting src is a) technically invalid code and b) only text fallback for those who get the polyfill but have JavaScript turned off. Until these new tags/attributes are natively supported in more browsers, though, it’s probably worth the trade-off to prevent double downloads for a whole bunch of people.

    Otherwise, great run-down of these options. O brave new world, that has such image tags in it!

  3. A very concise and thorough article on the matter, thank you! I am happy to see more coverage of responsive images lately. I myself built a grunt plugin to make you leverage built-in browser capabilities for responsive images.
    I am looking at giving it a major update, including less configuration (get the existing image sizes directly from the files), options how to set the src attribute (stay the same, choose the smallest image, none for polyfills) and support of the data-srcset attribute. I would like to hear your feedback on this and if this is something helpful. Highly appreciated!
    Also, I wonder why we still need x descriptors, since w descriptors pretty much handle also the pixel-density use case, given that you provide big enough images.

  4. Loads of articles about how to use srcset/picture, etc. But none seem to touch on actual usage within a CMS (like WordPress for e.g). How is a client supposed to create this kind of markup within a content editor?

    The other problem is bandwidth, the user might be on a big retina device but on 3g, but we’d still be serving a massive image because we only serve based on screen size.

    And as we get to super density screens, are we really going to be supplying 4k images? File size would be way over the top, even on broadband.

  5. So, what if I have an image in a column and want to use . I don’t necessarily know how big the column is, perhaps it’s a percentage of a percentage, or using flexbox, and I want the image to fill the column. How do I know how big it is in vw?

  6. @John: There are plugins out there, that help WordPress including the needed markup automatically.

    Also, consider using srcset is already a huge plus. As browsers get smarter they most likely will also consider available bandwidth or even user preferences.

    @Colin: Maybe the calc() function is of help to you. You could declare a size like calc(50vw - 100px), for example. That way you can account for a certain flexibility.

  7. @Stephen, your plugin will definitely be very useful. The extra syntax required to implement srcset and picture is one of the things I get asked about pretty often. Especially if the use case gets more complicated, so to automate this is definitely a plus. Ever considered writing one for Gulp?
    As for x-descriptors, I feel that for the use-case, it is a much shorter chunk of code to write.
    I too believe that bandwidth detection will become a thing that browsers can accomplish moving forward. As I follow the developments in the RICG, I realise it’s really a lot of work involved from polishing up the specs to cover all sorts of scenarios then browser vendors having to implement them.

  8. @Chen, great article, thanks for posting this! I’m a little confused about something. In the section about viewport based selection you say “As of the latest specification, if the srcset has any images using the w descriptor, then the sizes attribute must be present as well.”, but then go on to say “Because the first two examples display the same image at different quality levels, the srcset attribute alone is sufficient. “

    Can you clarify this a bit more? If the srcset attribute alone is sufficient, would you just leave off the w descriptor and use x instead?

  9. @Liz, the descriptors are part of the srcset syntax, both w and x descriptors each have their own uses. They are not used together, it’s either one or the other. w-descriptors provide the browser information on the width of the image, while x-descriptors provide the browser information on the pixel density of the image.
    When I mentioned the srcset attribute alone being sufficient, I was referring to usage of the element. requires srcset to be present, but srcset can work alone without picture.
    Hope this clarifies things a bit.

  10. Interesting to see the progression of how the placement of images will work going forward, but I still have my doubts of using CSS media-query-type statements in the HTML. From a philosophical point of view, isn’t this a step backwards from the goal of separating content from its styling?

  11. @Adam The dilemma there is that the browser needs to know details about the layout before the CSS gets loaded, that way they can start downloading the correct source. Jason Grigsby touched on this in his The Web Ahead interview (http://thewebahead.net/99). The gist of it is that the solution isn’t perfect, but it gets us really close to what we need for now. I imagine as the technology evolves, this will get better.

  12. I feel the title of this article is a little misleading.

    You reference using responsive images now and then later clarify that it’s only really supported by the latest browsers. While many people are making the switch, large-scale websites are still seeing high volumes of traffic from browsers as old as Internet Explorer 8 – so to reference it’s only supported in Microsoft Edge, immediately removes the ‘now’ proposition originally intended in the message.

    Neat, either way, though.

  13. Great post thanks! I always ran into issues using high-res retina ready images on wordpress. Even compressed at jpeg 30% google insight still says theres more room to compress… A solution anyone?

  14. @Luke your point is quite valid, I suppose I could have elaborated more on the very well-crafted Picturefill by Scott Jehl, which does offer support for IE9 and earlier.

    @z820workstation I’m not sure what algorithm Google uses but I do face this problem some times as well. I just make sure to run all my images through ImgOptim and live with the warnings. Although I’m interested if anyone has “beaten” the Google optimisation challenge as well.

  15. Interesting read. As some others have pointed out, I don’t see how this is practical from a designers/developers point of view or a client’s. This is a ludicrous amount of html to put in for every single picture in a website. I do massive redesigns with tons of content and this just isn’t practical. As the developer/designer, there is no way I would remember all the created resolutions for an image that would necessarily be standardized across the site (not too mention tedious and time consuming). From a client’s perspective, they can barely edit their content, let alone add pictures with complex queries. This is all aside from the fact that I’m normally lucky if I can get 2x sized images, let alone larger than that.

    What is way more practical is to either use some of the great server side solutions out now that work for any browser or simple javascript solutions like retina.js which I use currently due to it’s ease of implementation without tons of extra markup. Worst case scenario, if they had js off for some reason…the images are all standard html markup, they will just get the default 72dpi image.

    In the same vein, the only way I see this as practical is if it’s automated by developers, which inevitably will be for the basic reasons outlined above.

  16. This was an interesting article. I am going to practice this technique and see how it works for me.

    I wonder if there is a similar way to approach images while using them as backgrounds in CSS (ie: background-image:url(something.jpg); I know they are treated differently but often go through the same kinds of optimization. Is there a way to use the selective technique that way?

  17. Nice article. With increasing competition it is important to have responsive and attractive websites that makes the visitor stay for a longer period of time and have some interaction. Websites are no more an informative platform, but it is a strong marketing machine that leads to business improvement.

    Content management systems are capable platforms that makes the website development easier by providing unlimited features and functionalities to satisfy any business requirements. It is important to identify the right CMS that aligns properly with your business strategy. From the dozens of CMSes available, I feel WordPress is the simplest of all that even a non-technical person can use painlessly. It has various plugins that controls the optimization of images and make them responsive. Search for the right and secured tools for better results.

  18. As PHP developer this is pretty cool – but I imagine a jQuery function or a PHP function being able to take care of this fairly easily…

    In fairness though if the picture tag helps people save 5-10 seconds on their development time then all power to them.

    Images that resize are awesome!

  19. I believe there’s an error with this page. Under the section “Fluid-width images: viewport-based selection”, the snippet (#2) shows the sizes attribute using the “vw” unit, but in the below example it uses simply “w”.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

Nothing Fails Like Success

Our own @zeldman paints the complicated catch-22 that our free, democratized web has with our money-making capitalist roots. As creators, how do we untangle this web? #LetsFixThis