Not since the early days of web standards have I seen our community rally around a seemingly small issue: responsive images.
Over the last four years (yeah, it’s been about four years), we’ve seen many permutations of images in responsive design. From the lazier days of setting max-width: 100%
(the absolute minimum you should be doing) to more full-featured JavaScript implementations, such as Picturefill and Zurb’s data-interchange
method, we’ve spent a lot of time spinning our wheels, banging our heads and screaming at the wall. I’m happy to say that our tireless journey is coming to a close. The W3C and browser makers got the hint.
Further Reading on SmashingMag: Link
- One Solution To Responsive Images
- Simple Responsive Images With CSS Background Images
- How To Solve Adaptive Images In Responsive Web Design
- Responsive Images In WordPress With Art Direction
The State Of Responsive Images
In our search for the holy grail of serving the right image to the user, our attitude towards browser makers until now has largely been, “Forget you — we’ll do it ourselves.” I’m certainly no exception. We were so attentive to responsive images and were exposed to all of the guesswork and trials that are not typically released to the public that we got impatient (rightfully so) and did it with JavaScript.
The difference between a CSS transition and a responsive image is, of course, how they degrade. If a CSS transition doesn’t work, who really cares? Your interface might be a little jumpy, but the experience as a whole won’t really suffer because your users will still be able to accomplish their goal and consume the content they need.
That really isn’t the case with images. How does a new image tag degrade? The img
tag is so widely accepted that I couldn’t even find when the W3C recommended it as a standard, other than a small reference in the HTML 4.01 specification. Replacing or even expanding on the img
tag would be like telling Frank Sinatra to wear a baseball cap instead of a fedora — you’ll get some pushback.
Resource Problems
As responsive design grew in popularity and as the media through which users consume information became uncontrollable, we slowly realized that img
by itself wasn’t going to cut the mustard. We started asking questions like, “What screen size is the user on?” and “What’s the pixel density of the screen?” These questions fuelled our image techniques until we realized that screen size and pixel density have absolutely no relationship to the amount of bandwidth available to serve up a huge high-definition image.
The RICG began working on the picture
element, sharing its work with the W3C along the way.
The solutions got pretty complex. Talk of the picture
element started, and a group called the Responsive Images Community Group (RICG) appeared. The RICG began working on the picture
element, sharing its work with the W3C along the way. The result has led us to today and this discussion about all of the progress that’s been made.
The Introduction of srcset
Because most of the responsive-image community was on board with the picture
element and looking forward to it because of the great polyfills, such as Picturefill, it went ahead and released a well thought-out and fleshed-out document outlining something called srcset
, which is an extension of the standard img
tag. Yeah, I know — it feels like it came out of nowhere. It was also super-complicated and overly limiting by restricting you to (implied) pixel values and using a microsyntax that didn’t allow for scalability with media queries in the future. Luckily, the syntax has matured into what we have today, which is a fairly robust recommendation.
Most recently, Andrew Clark said it best when he tweeted, “Looked at the responsive images srcset & sizes attributes for the first time. Blimey it’s complicated.”
I couldn’t have said it better myself. Let’s look at what we’re dealing with:
<img alt="dog" src="dog.jpg" srcset="dog-HD.jpg 2x, dog-narrow.jpg 300w, dog-narrow-HD.jpg 600w 2x">
Three major attributes are in the snippet above: alt
, src
and srcset
. The alt
attribute is the same as it’s always been; src
is the fallback if srcset
isn’t supported; and srcset
is obviously the meat and potatoes here.
We can see three arguments in srcset
. The first is the image path. The second gives the browser information about the natural widths of the sources, so that it knows which resource to serve to the user (based on the user’s preferences and cross-referencing with the sizes
attribute – I told you it was complicated). The last piece sets the optional pixel ratio (2x
in this example specifies the high-definition image).
One thing I really love about srcset
is that the specification states that the browser should contain image-allocation preferences for certain bandwidth situations. This means you don’t have to worry about serving a 2x
image to a high-definition screen if that device is on a cruddy 3G connection. The user’s preferences should take over, and the browser would choose the appropriate image to serve.
Preparing for the picture
Element
After much complaining about our new weird friend, srcset
, the RICG continued working on the picture
element, which is finally getting some serious traction with browser makers… well, that is, with Chrome. The proposed syntax for the picture
element might look familiar because we saw it largely in the first version of Picturefill, and it’s not unlike how <audio>
and <video>
are marked up.
<picture>
<source media="(min-width: 600px)" srcset="large-1.jpg, large-2.jpg 2x">
<img alt="A fat dog" src="small-1.jpg">
</picture>
As you can see, a source
tag is in the picture
element, along with a normal img
tag. Just as we saw with src
in srcset
, the img
is a fallback. In the source
tag, we have what looks like a media query, alongside a srcset
attribute that contains the same image-source and pixel-density arguments as before. This seems like a nice clean way to popularize responsive images; we’re generally familiar with the syntax, so it should be easily adopted.
Browser Support
The srcset
attribute has been supported in Chrome since version 34. At the time of writing, it is not supported anywhere else. Mozilla appears to be working on an implementation (fingers crossed). Internet Explorer is nowhere in sight.
The picture
element has even worse support; it isn’t even in Chrome yet. But like Mozilla with srcset
, Google is currently working on implementing it. If you can stomach reading through a specification, I highly recommend it. Even though there isn’t much of a plot and the character development is pretty weak, it’s still a pretty good read.
Picturefill 2.0 was created because native support is reasonably close. You know we’ll need a rock-solid polyfill to use when the time officially comes, so let’s take a look at it!
Introducing Picturefill 2.0
Picturefill 2.0 was recently released as beta, and it’s quite a large jump from version 1. The RICG really aimed to create a one-stop solution for responsive images. The challenge was to create a script that allows you, the developer, to use any combination of the solutions currently being standardized, without bloating it to the point that not using it at all would be more lightweight.
Imagine polyfilling an image that would normally take 2 seconds to load using a JavaScript file that takes 10 seconds to load — it wouldn’t make much sense. Picturefill 2.0 avoids this by following the specification very closely (with some intentional omissions, which we’ll go over in a bit) and letting you use either srcset
or picture
or a combination of the two.
Picturefill is an responsive image approach that mimics the proposed picture element using div
s. (Larger version)
While we can’t reliably achieve everything in the specification using JavaScript (such as reasonably detecting bandwidth, which would be a user setting anyway), we can certainly take care of all of the pieces that are meant to be in HTML (i.e. elements and attributes). This version of Picturefill gets us one step closer to not needing Picturefill, which is the ultimate goal of anyone who has ever written a polyfill.
If you’re currently using version 1.0, I highly recommend upgrading to 2.0. It’s a big step towards a better solution to serving the correct image to the user. Some big changes have been made to the syntax and functionality. Let’s look at what’s new.
What’s New in 2.0
One thing that makes this polyfill different from others that I’ve seen is that it polyfills a concept, not just an unsupported block of HTML. Picturefill 1.0 used spans and custom attributes to mimic how we thought responsive images should work. For the record, it is a great solution, and I currently use it for many of my projects that haven’t been converted to 2.0.
In the last year or so, the specification for srcset
and picture
have matured so much, so we can now actually get to use something close to the real syntax. Picturefill is starting to look like a true polyfill, one we can strip away when real support shows up.
Installing and Using the Polyfill
If you’ve read this far, then you’ve probably dealt with some form of polyfill in the past. This one isn’t much different. Polyfills are supposed to be set-it-and-forget-it (to steal a line from Ronco), but because this is an HTML polyfill, you’ll need either to create the picture
element manually or use some form of HTML shiv to do it for you. Luckily, HTML shivs are pretty common and ship with toolkits such as Modernizr; just verify that picture
is supported in whatever shiv you choose.
<!-- Create the actual picture element if you haven’t already. -->
<script>
document.createElement( "picture" );
</script>
<!-- Asynchronously load the polyfill. -->
<script src="picturefill.js" async></script>
Other than creating the picture
element, you simply have to link to the script. Using the async
attribute is also recommended, so that Picturefill doesn’t block your page from loading.
Using Picturefill 2.0 With srcset
Let’s look at the syntax that provides the best support and that uses srcset
. It should look familiar because it has the same attributes that we saw when discussing the specification.
<img sizes="100vw, (min-width: 40em) 80vw"
srcset="pic-small.png 400w, pic-medium.png 800w, pic-large.png 1200w" alt="Obama">
The most glaring difference between this snippet and the specification is the absence of a fallback src
attribute, which was intentionally removed to prevent images from being downloaded twice in unsupported browsers. And, really, what would be the point of this if images were downloaded twice? Other than that, it’s pretty faithful to the specification, but it will probably evolve over time as the specification fleshes out and the polyfill matures.
The sizes
attribute tells the browser of the image’s size relative to the viewport. This often gets overlooked because srcset
is the buzzword now, but this attribute is equally important. If you’d like to learn more, Eric Portis makes a lot of sense of this “blimey complicated mess.”
Using Picturefill 2.0 With the picture
Element
The RICG did such a good job with this second version of Picturefill that the syntax of the picture
element should come as no surprise. It matches the specification very closely:
<picture>
<source srcset="extralarge.jpg, extralarge.jpg 2x" media="(min-width: 1000px)">
<source srcset="large.jpg, large.jpg 2x" media="(min-width: 800px)">
<source srcset="medium.jpg">
<img srcset="medium.jpg" alt="Cambodia Map">
</picture>
The biggest change between versions 1.0 and 2.0 is the removal of some traditional HTML (divs and spans) and the addition of newer elements (picture
and source
). Also, srcset
support is built in (heck, why not, right? It’s in the spec!). This is great step forward for this polyfill.
Use as many or as few of these options as you’d like. In line with the specification, if you don’t want to use the 2x
option, you don’t have to (and so on). The difference between this and the official picture
element is the img
fallback. You’ll notice here that the img
fallback also has a srcset
attribute, instead of a normal src
(which is widely supported). Again, this is to prevent double-downloading (it’s a real problem). The srcset
in the img
tag would also cause double-downloading if the browser supports srcset
but not picture
. This bug should get worked out in the beta version.
Like many good polyfills, Picturefill 2.0 can be executed programmatically by exposing a global function, picturefill()
. This allows you to use it in any ultra-hip JavaScript framework that you’d like. You can read about a few options for targeting specific images in the API documentation.
Degrading Gracefully
Earlier in the article, I alluded to the challenge of degrading the img
tag gracefully in unsupported browsers. This was another problem in creating Picturefill 2.0. Because it is a polyfill, the concept of unsupported browsers doesn’t really exist (kind of) — we’re using JavaScript to force it to work.
The edge case is this: If a browser doesn’t natively support picture
or srcset
and has JavaScript turned off, then you’ll get a frowny face. I can already feel your eyes rolling, but knowing the limitations of a system is important before you rely on it on a large scale. If a user were to come across a Picturefill’ed image in an unsupported browser with JavaScript turned off, they would see the image’s alt
text — a nice little way to reinforce the importance of descriptive and meaningful alt
text, isn’t it?
Alternative text is the fallback because the previous <noscript>
solution caused problems with browsers that support picture
or srcset
but have JavaScript disabled (two images would render). The group also explored adding a src
attribute to img
(as in the specification), but that results in double-downloading, which defeats the purpose of allocating the appropriate image assets to the user.
We’ve come a long way with responsive images. We can see the light at the end of the tunnel, but a lot of work still has to be done. And we’d love your help!
How To Get Involved
If you’d like to get involved and help out with the responsive-images movement, join the RICG via the W3C. If that’s too much, we’re always looking for people to try out Picturefill’s beta version and submit bugs through the issue tracker on GitHub.
You can also spread the word about great tools like Sizer Soze, which calculates the performance cost of not using responsive images.
Resources and Further Reading
- Responsive Images Community Group
- “The
picture
Element” (specification), RICG - “The
srcset
Attribute” (specification), W3C - @respimg, RICG on Twitter