To Picturefill, or not to Picturefill

Posted by Scott on 09/26/2014

This week over at the always-bustling Responsive Images W3C mailing list, a thread discussing whether we should more commonly use the srcset and sizes attributes instead of the picture element (answer: yes, we more commonly should) eventually led to another discussion over whether to polyfill these features in unsupported browsers. Some commenters rightly pointed out that these new standard features are designed to fall back gracefully to a default image in browsers that don't understand them (through the universally-supported src attribute), and thus advised against polyfilling the behavior for existing browsers:

The fallback behavior is not something to be afraid of. It's in fact just what we use on all the web today. Let fancy new technologies be just that, let browsers implement it when they want it, I advise agaist(SIC) using picturefill on something as important as Drupal. source

...and frankly, I agree. Well, at least I want to agree. But in practice, I've found that right now the answer is not always so clear.

As one of the authors of the Picturefill project mentioned above, it may be hard for me to sound objective about this. But I work on Picturefill because I think it's important and useful, and I always aim to scrutinize any code that we recommend. It's part of my job here at Filament to advise clients on how best to utilize web technologies, and I'm also just finishing writing a book that will attempt to recommend a responsible approach to serving images (among other things). Basically, I want to get this advice right, and frankly Picturefill is just one more piece of JavaScript in a pile of JavaScript that I'd rather not deliver to users unless there's a very good reason to do so.

So take that disclosure as you will. In what follows, I'll try to explain why I think it's a good idea to polyfill responsive images today (either with Picturefill or another responsive images polyfill).

Why polyfill anything?

A polyfill is a piece of JavaScript that patches support for a new standard feature in browsers that don’t support it. Generally, polyfills are great for both users and developers: users get to take advantage of whatever user experience improvements that feature brings, and developers get to code against a standards-compliant syntax that will live forever.

That said, polyfills typically come at a cost to users as well, since they require users to download and execute JavaScript in order to work. Sometimes, frequently even, that cost outweighs the benefits that the polyfill would bring. For that reason, the question of whether or not to use any polyfill should be taken seriously. At Filament, we try to use polyfills rarely if at all, and when we consider using one we base our decision on how much the polyfill will benefit users (with developer conveniences as nice, but less important criteria).

It's also important to us that a polyfill is designed to step aside when it encounters a browser that can handle the feature natively on its own. In fact, that's really what sets a polyfill apart from a framework, like say, jQuery. In using a framework, you tie your code to a non-standard API indefinitely, so your code will never gain independence of that boilerplate JavaScript file. That's not to say frameworks are necessarily bad – they’re very often worth their weight for normalizing code across many browsers alone. But with a polyfill, you write code against an API that will soon be supported natively in the browser, and at that time the polyfill will no longer be needed. This pattern of planned obsolescence is true of Picturefill, Respond.js, and any other polyfill we maintain or use here at Filament: the first step in the code is to detect if a feature is supported, and if so, it should do nothing. So in browsers that support the feature natively, the only downside of using a polyfill is that it adds dead weight to the codebase.

In essence, we use a polyfill when it brings an undeniable benefit to the user experience.

Why do we need responsive images?

The use cases for responsive image features are well-known: if you serve an image of the same size to all browsers, it can at best do one of two things:

  • it can look big and sharp for everyone while being too heavy for many users to download, or
  • it can be small and fast and look terrible on large and high-definition screens.

For many images, one source just isn't enough to serve every user appropriately, and that's why developers fought for a standardized approach.

Why polyfill responsive images?

Quite simply: it’s the responsible thing to do. Currently the picture element is supported in zero stable browser versions. The srcset attribute is now supported in a few browsers, but zero stable browser versions support srcset paired with sizes. Thankfully, users of “evergreen” browsers like the latest versions of Chrome, Firefox, Opera, Internet Explorer will gain support for these features very soon (and Safari too I'm sure!). But of course, users on browsers like IE 9 and older will never see native support for responsive images, and users on Samsung’s Chrome browser (the “Internet” app on any Samsung Android tablet) will have to wait for OS updates.

The problems that the RICG set out to address have existed for years, and developers have already been addressing them through whatever wacky means they could cook up. It's fantastic that we are gaining native, standards-based features to address these problems, but it's going to take a while for those standards to reach users that already need them. Using a standardized approach makes perfect sense, and yet the benefits that those features bring benefits all of our users, not just those in the latest browsers. A polyfill bridges that gap and makes sense for many of the sites we're building today.

Any drawbacks?

Yes, a couple. But I think they're outweighed by the benefits.

  1. Like any polyfill, there’s some JavaScript that users will need to download in order for the feature to work in existing browsers. Picturefill is lightweight but not insignificant (3.3kb compressed).
  2. Users in non-supporting browsers that are unable to load or run the JavaScript will not receive a fallback image; they will receive alt text instead.

Whoa... that second one! I know. I know.

Here’s the deal. If you specify a fallback image via a src attribute on your img (this is how you would normally specify a fallback image per the spec), any browser that does not yet support picture and friends will always request that fallback image over the network. This is true whether you use a polyfill or not, but if you do use a polyfill, that fallback image may not end up being the most appropriate image to display and another may be requested and shown instead. Regardless, the fallback image will be requested anyway and there's nothing the JavaScript can do to avoid that network overhead. So while you certainly can specify a fallback src while using a polyfill, it will end up costing some of your users in double-downloads, and that's not ideal.

The workaround recommended by Picturefill and the RICG is to omit specifying a src. If you do that, the polyfill can still ensure that all JS-enabled users in existing browsers see an appropriate image, and native implementations will of course show an image now and forever (without needing the polyfill). I should note that src is a required attribute per the specification; omitting src means your markup will be invalid. It will still work in browsers that support the standard, but it’ll be invalid. As always, we have to weigh the costs and benefits and make decisions about these things. The more noticeable downside of this workaround is that if you omit src, users in non-supporting browsers without JavaScript will not receive a fallback image - they will receive alt text instead. For many, this could be an unacceptable fallback. But alt text is a standard fallback, and I think it's often good enough for non-js use cases to consider the benefits this approach brings most users.

In closing...

On balance, I think responsive images are often important enough to deliver to all users today, and polyfilling the standard is the best way to do that. I hope that in a year or more, we'll see such broad support for these features that in many cases we'll be able to start pulling this script out of our projects. I'm not sure many of us can afford to do that today.

Thankfully, with a well-built polyfill we can bring all users these benefits now without worrying that we're placing a burden on users down the road.

At least for now, as both a developer and a user, I'm for it.