If you’re implementing responsive images (different images in HTML for different situations) and all you are doing is switching between different versions of the same image (the vast majority of usage), all you need is the srcset
attribute on the <img>
. Gaze upon this easy syntax:
<img src="small.jpg" srcset="medium.jpg 1000w, large.jpg 2000w" alt="yah">
It’s not just the syntax that is easy, it does a better job than <picture>
with <source>
s with explicit media
attributes (we’ll cover why in a moment). Plus it has the opportunity to be much better in the future with browser settings and browser improvements.
I’ve screencasted about this before, but it clicked better watching Mat Marquis’s talk at An Event Apart Austin and with Jason Grigsby’s post. I’m writing about it again here because I think it’s important for all of us to understand.
srcset
, the browser does the work of figuring out which image is best
With In the simple example above, all we’re doing is telling the browser about some images that we have available and what size they are. The browser then does all the work figuring out which one will be best.
Mat Marquis demonstrated this by showing how the browser approaches it with math. Say you’re on a device with a screen width of 320px and is a 1x (non-retina) display. and the images you have are small.jpg (500px wide), medium.jpg (1000px wide), and large.jpg (2000px wide).
The browser goes:
Lemme do some quick math that nobody cares about except me.
500 / 320 = 1.5625
1000 / 320 = 3.125
2000 / 320 = 6.25
OK, so since I’m a 1x display, 1.5625 is the closest to what I need. It’s a little high, but it’s the best option compared to those other that are way too high.
Now another browser visits the site. It’s also a 320px display but it’s a retina (2x) display. That browser does the same math, only then goes:
OK, so since I’m a 2x display, I’m going to throw out that 1.5625 image because it’s too low for me and might look bad. I’m going to use the 3.125 image.
See how that’s already useful? You’re letting the browser do the work of figuring out what’s best for it rather than you trying to figure it out.
The browser is going to get smarter still
Remember there is already benefit to using srcset
this way, but it’s going to get better yet. Think of srcset as suggestions or just extra information to help a browser decide. Ultimately it can do what it thinks is right. That means:
- A browser could offer user preferences regarding images
- A browser could start factoring in bandwidth
Yes, theoretical, but likely.
And if you go down the <picture>
with explicit sources, the browser has to do exactly what you say and not make choices for itself. Now, <picture>
can be set up such that it does exactly what srcset
it going to do right now, it’s just a lot more verbose and doesn’t leave room for improvement.
sizes
Also, We didn’t talk about the sizes attribute at all here, on purpose. It’s actually not that bad to just leave it off. In that case, it assumes sizes="100vw"
, which is saying:
I assume that when you use an image, it’s going to be the entire width of the viewport.
That’s usually not an awful assumption to make.
If you want, you can get all kinds of specific about it. You can use sizes to match your CSS layout exactly and tell the browser exactly how big that image is going to be on every screen size, matching how your breakpoints work in your design. That can get a little complicated and honestly it might be a little dangerous because you’re putting CSS stuff in markup and you know how that goes. Eric Portis just wrote about this. Ideally it can be automated or injected server-side.
I also think kind of “generic” sizes attributes might be useful. On a kinda generic blog-ish site, maybe something like this is smart within content:
sizes="(min-width: 800px) 50vw, 100vw"
Meaning: “If the browser window is wider than 800px, this image is probably going to be displayed about half the size of that. If it’s smaller, it’ll probably be full-width.”
Why talk about this?
Again: the vast majority of responsive images use isn’t “art direction” based. Art direction is a fancy use case, and please do it to your heart’s content. <picture>
is great at that.
Most responsive images uses will be: “I have multiple versions of this graphic. Here they are, use the right one.”
This is a very confusing subject. It needs to get thought about and written about so it can shake out and become a more ingrained part of our collective front end developer consciousness.
Tim Evko created a WordPress plugin for responsive images. It leverages WordPress’s ability to make smaller versions of images. Then you click the image you want, and it ultimately outputs the responsive images code needed for it. At the moment, it uses <picture>
. That’s because <picture>
is up in the collective front end developer consciousness in a much stronger way than srcset. Tim is trying to understand all this so he can figure out if and how to change that plugin.
@Tevko @brad_frost srcset/sizes = information to help browser decide which best. Picture w media attrs = explicit DO THIS ONLY
— Chris Coyier (@chriscoyier) September 29, 2014
When?
This is tricky too.
If you want it right now and want great browser support, you need to polyfill it. But that has some potential downsides. So for now you’ll have to make that call for yourself, I’m not sure there is a best practice for all scenarios yet.
Great stuff. Very useful thanks.
I am convinced that the plugin needs to be changed, and will make that fix shortly! Only thing left to decide is how many default image sizes to create, along with the idea of leaving the sizes attribute off, or including a typical blog default. All are welcome to join the conversation on Github!
One other thing to mention (as I understand it, although I can’t claim to be an expert):
If your browser size changes — e.g. because a desktop user resizes the window or a mobile user switches from landscape to portrait — the <picture> syntax obliges the browser to switch images, downloading a new file. Which is really bad for bandwidth, and overall webpage performance, if the new file is just a scaled-down version of the file that the browser was already using. With srcset, the browser can see that the old file will still work, and scale it as it normally does.
I think the point is that
picture
is when you are more afraid the way the pic looks like for the user andsrcset
is more when you just need to present something that quality/readability is not a problem.Yep—that’s not in current (planned) implementations, but Firefox been thinking it over.
That part of the spec was left intentionally vague, so browsers have room to make optimizations exactly like this. There’s a lot of room for future improvements.
It looks more and more like the browsers are pushing development more than the W3C.. This is in Chrome 34, if FF supports it and it’s in IE12, then it’s good as accepted.. but then what happens if the W3C changes the standard and/or merges the picture and image tags…
The W3C is comprised mainly of the main browser vendors
Yup. Not only that, the w3c intentionally doesn’t put anything on a standards track unless browsers are interested in implementing it (or, more often than not, have already implemented it). Spec already doesn’t always match implementation — imagine how much worse it would be if there was no coordination with/ support from vendors.
Does anyone now why using “ does not allow the browser to make decisions? I’m happy to use and thanks a lot for this post Chris, but I was just wondering why.
Using what? It is showing just “” for me.
<picture> is intended for when you actually need to swap in different pictures (not just different resolution) at different sizes.
Examples:
If you have a banner image that you want to fill the entire window, you might have very differently-cropped versions of the image in portrait and landscape mode. Currently, you would have to use CSS background image instead of a markup image if you wanted to swap out different image files.
If you have a diagram with text, you might have a more compact version, with less text displayed in a larger font size relative to the rest of the image. (You can sort of get around this with a single SVG image file, but it’s a big headache and requires lots of custom CSS to hide or show the text.)
In those situations, the layout/design could become unusable, or at least ugly, if the browser inserted the wrong file.
Unfortunately
srcset
andpicture
are not broad supported by currently available browser according to caniuse.com.Hope they start implement it at least by the end of year.
@Victor: Using img with the srcset attribute is safe even with browsers that don’t support it, because you use a src attribute as well. Browsers that support srcset will use the new features, those that don’t will fall back to the src attribute.
You can also use the PictureFill polyfill to add support for the picture element and srcset to older browsers.
Seems like the main mobile browsers support it, so using src for your desktop image and srcset for the smaller breakpoint images would work.
Though that relies on the mobile browsers not downloading the src as well as the relevant srcset image. Anyone know if they’re smart enough to avoid that?
No worries: there’s no double-download using
src
andsrcset
—likewise with theimg
fallback in browsers that supportpicture
. Things can be tricky in that department when you get into polyfilling, but if you’re relying on the native fallback patterns there’s no risk of a wasted download anywhere.I have been using picturefill to swap out different sizes of the same image based on my site’s breakpoints. So if the screen is small it gets the smallest image (dimensions and file size). With srcset if the small screen is retina it won’t get the smallest image anymore. If I want it to for performance reasons, I should really stay with picture, right?
So if I understand correctly, it is trivial to support retina images in our CMS where they are currently displayed at actual size. We’d start by adding a srcset with the normal image (also in the src attrib) and the 2x image (with sizes in pixels), then setting sizes=”width of original image in pixels”. I guess it only gets tricky when you need to be trickier about the size the image gets displayed at…
The 100vw assumption for sizes is interesting, but I suppose this process has to operate in the absence of CSS, so it can’t assume 100% of container width or similar.
Nice post chris…your blog keeps me updated and never makes regret web design.
Why is it better to use 500w and 1000w in srcset instead of just putting the smaller image in src and the larger image in srcset with 2x?
How to use responsive images as background image?
Media queries!
Very informative, thanks!
So basically
srcset
on animg
tag is ready-to-use because it doesn’t have any drawbacks if a browser doesn’t support it. No double downloads. Just improvements.I found two sentences that may need to be corrected:
Hi Chris I have seen those article linked in many sites finally get there… Useful article, as always.
A bit of shameless self promotion:
You can check out my WordPress plugin, Responsify WP, that supports both
picture
andspan
as markup patterns. It can also take care of background images.A new version that supports srcset/sizes will be released in a couple of days :)
But I must say, I found it very hard to wrap my head around how the srcset/sizes attributes worked together.
In cae you are using the w descriptor. I would recommend to also describe the src fallback image inside the srcset attribute:
I’m currently using this on a site I’m developing which is great for image clarity, but I think it needs to address bandwidth somehow. I’m saving 1x images optimized at 60%, 2x images optimized at 20%, and using svg everywhere I can which helps, but it’s not making much sense when someone has 2x screen on their phone and you load the biggest image (so it’s basically pretty) which is just odd considering not long ago we wanted to load smaller images so sites and images loaded faster… Now we’re loading bigger images.
We spent so much time reducing http requests, sprites, then icon fonts, now svgs for speed speed speed.. so now lets load the biggest image we can solely based on pixel density. Help me understand?
Thanks!
Well SVG is for more than just speed, but hopefully the point wasn’t lost.
That’s why the next advancement in responsive images will be browser options that let the user decide whether they want the high-res image or the low-bandwidth file. For mobile browsers, that would ideally allow the user to have different settings depending on whether they are using mobile networks vs wifi — or maybe even more specific, factoring in roaming fees and low-speed shared wifi.
Once the browser has this data about user preferences, it would factor it in to the decision about which file in a source-set list to download. But as Chris (the other Chris) describes in the post, these browser optimization choices would only apply to multiple values within a
srcset
attribute, not to multiple<source>
elements within a<picture>
.Opera already has a browser mode to reduce download sizes, where you can actually set the browser to download files compressed on Opera’s proxy servers in order to have faster, if lower-res, websites. I suspect they already (or will soon) factor in
srcset
options in order to select the lightest file for people using this “Turbo” mode.Well, a complex one to implement. However, a useful one.
Chris,
This is the first Time I had came to know that images can be made responsive. Will try to implement this.
Will get back to you If I had any issues
Thanks Chris, nice read! What still bugs me with both concepts are the duplicated breakpoint definitions on each element. There is a better, more elegant solution for this with anzeixer.js, sadly its not very well known – so please have a look and spread the message! ;) I wrote a blog post how to implement a simple responsive image solution based on this: http://www.andre-abt.com/2013/09/16/responsive-breakpoints-and-images
Really awesome article on how to use srcset. I think that too many developers are actually not using browsers built in features , it can really help you out a lot!
I think once this is supported by all browsers I will certainly start to use srcset, seems like right now it makes sense to use width =”100%” for now, or some kind of percentage. Thanks for the share and the future heads up!
Teelah, you can use both.
Example:
You have an image of the same house in 3 different sizes. Extra-large (1600 wide by whatever high), large (1200 wide by whatever high), and medium (etc.). You can set that image container to 100% width while only loading the appropriate image inside depending on the display area as well as pixel density.
I pulled together different parts from old code snippets to do something similar a few months go.
You can specify which image for which view mode, plus have a default src for the good old spinner if you attach lazy load.
The height and width can be specified or dynamic calculated for the image in order to pass google page speed requirement of image dimensions for img (Page repaint)
Not perfect but it fits my needs for Bootstrap 3 responsive images.
https://github.com/ArranM/BootstrapImageReplacement
and the js is here:
https://github.com/ArranM/BootstrapImageReplacement/blob/Master/BootstrapImageReplace/Scripts/ImageReplace.js
I hope it helps someone one day.
Thank you for sharing this great method for responsive images. It works like a charm!
You’re all on the bleeding edge; the users aren’t.
Really useful post, and one which I’ll start implementing.
Before this post I’d been looking thinking about using a placeholder image (less than 1kb) and then setting a number of images as data attributes (small, medium and large), loading a particular image in based on screen width with JavaScript. This is a much better solution though. Thanks.
Great article. Excellent explanations.
Hacking srcset and sizes to force art-direction crop in small devices:
Is there an alternative to this when using background images? I find it more useful for background images since these are the huge images that need to be scaled most of the time.
@Jose: Just use different “background-image” attributes on your target elements inside your media-queries.
@Andre: I’m familiar with this technique just wondering if there was a way around explicitly specifying a unique background image for each breakpoint. Thanks.
I have a question concerning the HTML example in the original post: How exactly does the browser know that the small image has a width of 500px?
From my point of view specifying an image only in
src
but not insrcset
only makes sense with the 1.5x/2x/3x syntax. When specifying image widths (200w, 400w) insrcset
the fallback image should be specified insrcset
as well.Or am I missing something?
Good question. I think ideally small needs to be replicated in the srcset attribute for this to work properly:
<img src="small.jpg" srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 2000w" alt="yah">
Can you confirm Chris?
Overall a good way ahead for serving responsive images into multiple devices with multiple resolutions.
Does anyone know a solution for manipulating images with Javascript/jQuery that are generated using the srcset method? For instance, this very simple jQuery image swap code breaks in Chrome/Opera as it seems to completely ignore the “src” attribute.
Ideally I wouldn’t even want to grab the “src” value anyway but I don’t see where Chrome/Opera specifies which image it chose to be able to then grab that value and use it elsewhere.
Any thoughts or ideas would be appreciated. Thanks!
Nevermind. Looks like it is working now at that link.
I’ve been looking into src-set, but it seems that whilst we’re talking about it a lot, the actual practical use without polyfills is pretty much not possible or practical.
At the time of writing this:
* Firefox needs a developer flag to be turned on
* Mobile WebKit only supports the -x syntax, which is next to useless for an image scaling from small up to massive (e.g. a hero image). No -w syntax support yet as of iOS 8.1.
* No support in Android’s AOSP browser as of 4.4.4
* No support in IE
* Perversely, Chrome 38 on desktop (and Opera now by extension) has the best support, when we really need this in particular for mobile.
It’s nice to talk about, and it’s nice to compare it to picture (which has even less support), but it seems even srcset just isn’t ready to be used in production yet – and practically not for a while yet. Sigh…
@Mike I wholeheartedly agree.
I just got stuck on this for a while. When you use a
sizes
attribute, make sure you put your narrowest image size first. Not the smallest media query.E.g.
(min-width: 62.5em) 25vw, (min-width: 30em) 50vw, 100vw
not (which one might expect)
(min-width: 30em) 50vw, (min-width: 62.5em) 25vw, 100vw
I prefer much easier solutions like Bildero, by uploading your source image (i mean you don’t have to create small.jpg medium.jpg and large.jpg) – just the orginal image and by inserting simply JS you are able to have truly responsive images.
Bildero automatically detects your visitors screen resolution and create on the fly perfecly fitted image from your orginal one. I recommend it for everyone becaouse it saves much time and money (time is money so i saves money^2 :D ).