Picturefill 2.0: Responsive Images And The Perfect Polyfill
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
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.
The State Of Responsive Images
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.
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
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 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
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
<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
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.
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.
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.
picture or a combination of the two.
Picturefill is an responsive image approach that mimics the proposed picture element using
divs. (Larger version)
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
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.
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
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 (
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,
Earlier in the article, I alluded to the challenge of degrading the
The edge case is this: If a browser doesn’t natively support
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
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
pictureElement” (specification), RICG
srcsetAttribute” (specification), W3C
- @respimg, RICG on Twitter
- 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