I’m probably a bit rare in that I rather enjoyed trying to keep up on the responsive images thing. It’s an interesting problem that bred lots of interesting solutions. The whole thing is starting to wrap up now though, now that the official solutions are:
<picture>
and friends<img>
withsrcset
andsizes
The problem is: I don’t really get it. I thought the original picturefill was pretty simple. List a bunch of sources with media queries. First one to match, that’s the one that gets used. That made sense to me. This new stuff is a bit different. Solvable problem! Just like everything else, I need to figure it out.
That’s why I was totally sympathetic to Martin Wolf’s post “The new srcset and sizes explained” where he was struggling with the same problem. So I used that as a starting point for playing myself.
Here’s some things I’ve learned.
This part makes sense I think:
And this is where it gets weird:
Why are we telling the browser how big an image is? It’s a browser. Shouldn’t it know how big images are? Well it does, but only after it downloads the entire thing. Smarter decisions can be made right off the bat if it knows this information sooner. So we just tell it. You could lie. Or be wrong. Which is weird but whatever.
Now that you have those different image options listed, you’ll need to also use the sizes
attribute. This provides more information to the browser about what how to intend to display the image so it can use that in making a choice about which.
The sizes attribute is also weird to me:
Again, it’s all about intention. The sizes attribute doesn’t actually have any effect on the size the image actually renders. (I was wrong about that in the video.) That’s left to the real actual image size itself, or (more likely) CSS. We’re just giving the browser information about what we intend to do so that it can make a smart choice about which image to use. I think it feels weird because we could again, lie, or be wrong, which is unusual thing in HTML.
If we provide all this info, and do it right, then the browser (or the polyfill) can make a smart choice about what image to display.
Let’s take this example:
<img
src="small.png"
srcset="large.png 1280w,
medium.png 640w,
small.png 320w"
sizes="100%"
alt="whatever">
Say we’re on a 1x screen. Because we’ve told the browser we’re going to be using these images as big as we possibly can (100% of the viewport), the “breakpoints” for when the browser will flip out the images will happen at 1280px, 640px, and 320px, the same exact sizes as we’ve told it the images are.
If we’re on a 2x screen, those “breakpoints” will cut in half (regardless of what we actually do to size those images) and will be at 640px, 320px, and 160px.
Now let’s say we use the same images, but we know a lot more about our page layout, and used something like this:
<img
src="small.png"
srcset="large.png 1280w,
medium.png 640w,
small.png 320w"
sizes="(max-width: 500px) 250px, 500px"
alt="whatever">
Here we’re saying (with the sizes
attribute), if the viewport is 500px or smaller, we intend to display the image at 250px wide. If the viewport is wider than that, display the image at 500px wide.
That would match up with CSS like this:
img {
width: 500px;
}
@media (max-width: 500px) {
img {
width: 250px;
}
}
On a 1x screen, you’ll always get the 320w (small) image when the viewport is 500px wide or smaller, and you’ll always get the 640w (medium) image when the viewport is larger. You’ll never get the large image, because it can tell you’ll never need that many pixels.
Ona 2x screen, you’ll always get the 640w (medium) image when the viewport is 500px wide or smaller (because it thinks it needs 500px of pixels and the small isn’t enough at 320px), and you’ll always get the 1280w (large) image when the viewport is larger. You’ll never get the small image, because it’s never enough pixels to cover what you’ve told it you intend to render the image at.
Actual Sizing
Remember the actual sizing of the image is still up to you. I would think in the majority of cases it’s you doing it through the CSS. And the CSS always wins. What you declare there will be the rendered width of the image no matter what happens with the srcset
and sizes
stuff. That just works out which image will be shown.
This is what makes the sizes attribute a bit tough. Let’s say you have something like:
.container {
width: 80%;
}
.container article {
width: 50%;
}
.container article img {
width: 33.33%
}
That’s not unusual at all. So now what size do you use in the sizes
attribute? That would be 13.33% (multiply them all together) because that number needs to be relative to the viewport, not the container. And that doesn’t take into account margins and padding and stuff on those containers, so it’s kind of a guess. I guess close counts in horseshoes, hand grenades, and the sizes attribute.
Then let’s say a media query comes along and the body actually becomes 75% wide on top of all that. You need to know that so you can adjust what you think the rendered size of the images will be. Your sizes attribute might become:
sizes="(min-width: 500px) 8%, 13.33%"
Then go through that again for every layout media query you have that affects content images. It can get a bit complex.
Practical Sizes?
I suspect most real world usage will use something like:
<img
src="small.png"
srcset="large.png 1280w,
medium.png 640w,
small.png 320w"
sizes="(min-width: 500px) 50%, 100%"
alt="whatever">
Assuming that content images will be around half the size of the browser window on large screens and the full size of the browser window on small screens – just let the breakpoints happen where they happen. You’ll still get a pretty decent choice this way without slaving away over matching all your media queries exactly.
And remember these are content images. HTML tends to last longer than CSS or JS does, especially when it’s content.
Other Things To Know
You can also specify if an image is 2x or 1x with srcset. So a really simple use case can be:
<img srcset="small.jpg 1x, large.jpg 2x"
src="small.jpg"
alt="whatever" />
That alone is pretty useful. Don’t mix it with specifying widths. As Eric Portis says:
And again let me emphasize that while you can attach 1x/2x resolution descriptors to sources in
srcset
instead ofw
descriptors, 1x/2x & w do not mix. Don’t use both in the samesrcset
. Really.
And remember when I said the original picturefill was easy? The new <picture>
can be that easy, but the <source>
elements inside <picture>
also support srcset
and sizes
. That means you can get very specific. It adds another layer to this:
- You decide which
gets displayed based on media queries
- That
has it’s own srcset/sizes, for determining exactly which src gets used
Here’s an example from Eric Portis’ recent Smashing Magazine article:
<picture>
<source media="(min-width: 36em)"
srcset="large.jpg 1024w,
medium.jpg 640w,
small.jpg 320w"
sizes="33.3vw" />
<source srcset="cropped-large.jpg 2x,
cropped-small.jpg 1x" />
<img src="small.jpg" alt="A rad wolf" />
</picture>
Links
- Martin Wolf’s article that inspired this
- Picturefill is the polyfill you want to be using.
- Smashing Magazine article on Picturefill 2.0 by Tim Wright
- Eric Portis on why Srcset and sizes exists and what it solves better than media queries
- Eric Portis with more about the new
<picture>
See the Pen srcset & sizes testcase by Chris Coyier (@chriscoyier) on CodePen.
This is some great progress with the spec finally being implemented.
I guess I’m kind of more curious in how CMS’s will allow for it to be utilised and as to whether clients will grasp the idea.
Least i know that I can start using this stuff on my recent projects with the polyfill.
I managed to get this working in WP for 3 different sized header images for large, medium and small viewports.
Just add three image sizes to your functions.php like so:
and then for the template drop this in:
<img
srcset=" 1170w,
750w,
500w”
sizes=”100%”
alt=””>
Thanks for another great tutorial.
Hadn’t heard about srcset until now but it looks great. Plus, I can take still use this on client projects by letting the CMS take control of creating/ loading multiple versions of their image. Awesome!
Great writeup!
I’ve seen a few people now who think that
sizes
effects, rather than reflects, the size of the image. It is kinda weird that it doesn’t.But I’d rather describe the problem to the browser than prescribe a solution (which is what attatching media queries to sources directly does). Relates to this bit of Jeremy Keith’s recent “Seams” article:
The browser dosen’t know either the source sizes or the destination layout size when it needs to pick a source, because of preloading. So we just tell it, and let it make the best decision for the user, given everything that it does know (e.g., the user’s bandwidth, a user-settable preference, their
device-pixel-ratio
, or whatever).If we need to prescribe specific sources for specific breakpoints, we can step in and take control with
picture
andsource media
.Yoav’s Responsive Image Container idea would make this all much simpler.
srcset
w
information gets encoded in the file itself in a header; the browser preloads that header and a base image but only loads the bytes it needs to “upgrade” it to the destination layout size after it has loaded CSS and figured that layout size out for itself, so we don’t needsizes
… but it’s a long way off.One nit with the examples:
%
is no longer valid insizes
; it was depreciated in favor ofvw
to make it clear that you’re talking about a percentage of the viewport width, not the parent element.Nice as always..Chris!
We’re going to need a cookbook for this stuff haha
Great overview Chris (following on from Erics’ overview on his own site and Smashing recently).
I can feel new brain synapses developing with each pass over these articles and each new codepen. Hoping to have a list of patterns for this as part of going over it time and time again, if you’re working on something similar give me a shout and I’ll send my stuff through.
Thanks for all of your hard work in the community. Great Work!
Hi Chris, what happened to your Rode Podcaster mic, sounds like you’re sitting in an oil barrel!
Yeah trying out some new stuff (blue yeti mic thingy) – gotta fix that.
The third code block should be like this:
You missed the img selector in @media
Good catch! Dumb me. I probably had it nested but then moved it out because that’s a weird thing to chuck in there in an article like this so moved it out and forgot how that works derp.
Is this method only compatible with newer browsers? There doesn’t seem to be any mention of compatibility, is it safe to assume this works with all browsers then?
The <picture> element and the srcset attributes are currently not supported by any browsers without the help of a polyfill. The Picturefill polyfill included in the list of links at the end will enable both features in most browsers. The Picturefill website has more detailed documentation about browser support.
Now that the spec is being nailed down, it is likely that the major browsers will begin supporting it natively in the near future.
No. It’s not. And if you’re interested in front end development this site should be your bible: http://caniuse.com/#search=srcset.
I will use this in my current responsive website project.
Tested this on windows IE7, IE8, IE9 and works just fine.
I need to see how it will work on with a responsive Slider
Great walkthrough! Only on question left: If we provide the browser with detailed “sizes”-info (max/min-widths + relative widths)—would there be no or little use for “2x” in srcset? Does this solution handle resolution when picking images, even without the 2x-thing?
The most important advice is use EITHER the
w
values OR thex
values, never both.Good:
Bad:
It’s good to see the final solution includes a backward compatible img implementation, the picture element was always going to be an issue with legacy browsers.
As Mr Burns would say “Excellent”.
Its excellent solution, instead of using the
img{width:100%;}
in CSSNot particularly current nor maybe even relevant to this thread, but I’ve been using the code below for a few years and get the desired results ( in this case responsive bg images)
In the WP header file
The key rules in the #wrapper ID in style.css
This seems to get it right and because I’m using jQuery IE8 even plays nice (with, to be fair, the default use of css3-mediaqueries.js)
That being said, I’m sure I could learn a thing or two from taking a look at these new standards.
Peter
Forgot to mention the URL for this project
http://projects.b2webservices.com/PCP4
Maybe a stupid question but I am little bit confused. So in the future I can use BOTH responsive image solutions?
picture and friends
img with srcset and sizes
At the moment “picture” seems more logical to me but I think like Martin Wolf I need some time get it.
Nice technique using srcset, a new one to me, thanks.
I want to use it on eshop with one simply rule – display low-res images on mobile phones and better quality ones on desktop. I asume that with doing this, i could save quite a lot of data trafic for mobile users so as a sideeffect increase for them the speed of the web. I know that mobile phones now got sometimes very high resolution, so i would like to target lowress displays the low resolution displays or higher with some multiplier. And i would like to do it with shortest possible html code with only 2 img versions (btw i heard that e.g. jpg with compression lvl 60 resized to 50 % is nicer and data-smaller, then nonresized quality 90 jpg) and with good enough compatibility (most used android, ios, winphone mobile browsers). What code would you reccomend?
Great stuff as usual!
I noticed that if you add the src fallback, both the fallback image and the intended image are both loaded by the browser.
Also, the img srcset option does not seem to work in mobile Safari on my iPhone 5. I’m still seeing the extralarge.jpg in this Picturefill demo: http://scottjehl.github.io/picturefill/examples/demo-01.html
Please, check out my idea how to always show better image for client, according to it`s screen resolution and image aspect ratio: http://jsfiddle.net/iegik/cA7SV/
Great article, RWD is feeling complete. Speaking of WP, I wrote a function to use in the theme templates when calling the post_thumbnail:
Great article. I’ve just started implementing Picturefill in WordPress and have been using this function on feature images:
Any ideas on how to modify this to remove the picture element and only include srcset?
nice
I am confused.com (have to read again … and again)
It all looks like a load more ruddy work (trail / error / trial) to me … and trying to explain that to clients ?!!?!?!
I am old school, brought-up on penny-pinching bandwidth and 48K Dial-ups … every pixel, character and byte was squeezed out of HTML/CSS/Script … now it’s BLOATSVILLE !! Especially ruddy WordPress which already hogs TB of used server space/ creates unused images litke there is no tomorrow and 1000’s of php files to serve a few ruddy pages!
I quit !!__ (rant rant rant !!)
Great article actually .. thank you for sharing.
Hi,
I’m just wondering, If I want to use srcset I must have picture with different size as example :
I want to use srcset for my image named ‘pic.jpg’ it had 1280×1024 px, If I want to use it for I pad, I must re-size it ( to Ipad dimension) and save it ‘ipad.jpg’ and so on for all screens ?? Or just one picture and the srcset will do the other?? Because to me is better to use one picture in my ‘Media folder’ and give it a style in Css file to re-size it based on screen device than use 3 or 4 pictures and give it a style in my Css file
This article is great, but in my humble opinion i think you should educate your readers about browsers that don’t support the srcset attribute. People shouldn’t only know how to use this technology but also how they would write a fallback for older browsers which achieves the exact same effect.
For people who are interested in which browsers support the srcset attribute: http://caniuse.com/#search=srcset.
This is pretty cool stuff! Seems simple, elegant and quite frankly very useful. I haven’t had time to play around w/ it yet but it’s on my to do list. I am curious if there have been any issues on mobile platforms or if that too is seem-less and supported???
Thanks!
Is anyone able to pen included at the bottom working in chrome 41? CanIUse(http://caniuse.com/#feat=srcset) suggests this is supported but the images are not swapping out.
Pen: http://codepen.io/chriscoyier/pen/reFLJ
I’m experiencing the same thing. Any input Chris?
The picturefill demo doesn’t seem to be working either for me. All I see is extralarge.jpg
http://scottjehl.github.io/picturefill/examples/demo-01.html
Hey ya’ll –
Are you trying to resize the area smaller and expecting to see the larger image get swapped out by the smaller one?
If so, that’s not how it works anymore. Spec change I think, and Picturefill updated to match. If the browser already has the larger image it won’t swap it out for a smaller one (because why would it, it’s more efficient not to).
Almost forgot about this comment. Ah, ok. Didn’t realise that. That is a much smarter implementation though, as you state. Thanks Chris.
yeah, images are not swapping correctly, i tried to resize, its not working, im using chrome and firefox.
In your “Practical Sizes?” section the code for sizes is
and you state
I think you meant to say
You are 100% right, fixed that.
I’ve often had to use background image options in order to manage images, and generally the images that pose the biggest problems are photos that are full page photos that have to be laid out in different orientations, and it mobile and have a focal point in the photo (such as a person’s face). Getting the photo to line up consistently and scale is really impossible. Which then requires 3 to 12 different size images. This is why most people use a generic photo in the background with a single button in the middle. Because it doesn’t matter how the photo is laid out.
Helloo
Regarding bandwidth –
Does this load only the image that the browser choozeez??
Or all zee imagez in the srcset?
Chris,
According to WHATWG, percentages are no longer allowed. Section 4.8.4 says:
https://html.spec.whatwg.org/multipage/embedded-content.html#attr-img-srcset
“Percentages are not allowed in a , to avoid confusion about what it would be relative to.”
Hi Chirs,
I have one question, Loading retina images for user having slower mobile connection will slow down the site.
How can we prevent loading retina images for mobile devices and load standard image?
Thanks
There have been some changes since this was written in 2015, mainly the sizes slot width does no longer accept percentage.
I updated the Codepen example.
https://codepen.io/fgeierst/pen/yLaPwWW
@Florian, @Chris
This https://codepen.io/fgeierst/pen/yLaPwWW doesn’t seem to be working, as of Chrome 87.
Any thoughts on why and a fix?