read

Images that download faster than a racing ostrich

We've been considering how to use responsive images when serving stuff.co.nz, and it seems that srcset is coming of age, after a bit of a tortured start.

As of writing this post, it's either supported or to be supported in the next release of all the major browsers, and has a good polyfill in picturefill.js, meaning that there's not really a good reason not to use it.

Devilish details

However, as is often the case, there's a couple of wrinkles to consider regarding implementation.

We want to be able to serve responsive images to both those browsers that natively support srcset and those that don't (via the polyfill).

We also want to be able to ensure that users get an acceptable image experience when they either have JavaScript turned off, or when JavaScript is broken.

It's this last requirement that makes things interesting; there's a good analysis by the gov.uk Government Data Service that shows that around 1 in 93 users don't have JavaScript. Of this number (1.1%), it turns out that the smaller fraction (0.2%) is those that have JavaScript turned off; the majority of users without JavaScript (0.9%) are those where the JavaScript failed during download.

So, we need a solution that allows users of older browsers with broken JavaScript to be able to see an image, as the polyfill won't be able to do the job.

However, according to this post from the Filament Group by Scott Jehl, the picturefill.js author, the recommendation is to not specify a src attribute in order that older browsers without srcset do not download an image (which picturefill.js may then replace).

If there's no src attribute specified on the img tag, then the user with an older browser that's unable to run the picturefill.js polyfill will only see the value specified by the alt attribute.

It seems that they consider that this is a lesser evil than having the browser download possibly two images (i.e. as specified by the src attribute, and then by the polyfill).

But, as mentioned earlier, we know there's around 1.1% of users that don't have functional JavaScript, many of whom could be using an older browser (i.e. without native srcset support), and we do want them to see an image rather than the alt attribute value.

Our initial solution

Our first attempt at solving this is below:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Image test</title>
    <style>
        .invisible img {
            visibility: hidden;
        }
    </style>
</head>
<body>
    <img class="invisible" alt="ponytailgate"
         srcset="images/ponytailgate_1240x698.jpg 1024w,
                 images/ponytailgate_620x349.jpg   620w,
                 images/ponytailgate_320x180.jpg   320w,
                 images/ponytailgate_160x90.jpg    160w,
                 images/ponytailgate_80x45.jpg      80w"
         sizes="(min-width: 620px) 620px,
                (min-width: 320px) 320px,
                (min-width: 160px) 160px,
                (min-width: 80px)   80px" />

    <script>
        [].forEach.call(document.querySelectorAll('.invisible'), function (el) {
            el.classList.remove('invisible');
        });
    </script>

    <noscript>
        <img src="http://images/ponytailgate_320x180.jpg">
    </noscript>

    <script src="js/picturefill.min.js" async></script>

The thinking here is that:

  • we hide the image initially
  • we don't specify a src (thereby avoiding a possible second image download)
  • if JavaScript is enabled, we unhide the image
  • the noscript tag serves to show users an image to those users that have JavaScript turned off

This approach works to a point, but you might have noticed the flaw: the noscript tag will work for those users that have JavaScript turned off, but not for those uses that have JavaScript turned on, but where the JavaScript download failed — these users will still only the alt attribute value if they're using an older browser.

Our final solution

We decided that, as it seems like there's no optimal answer whereby we could provide a single-image solution to all users, we had to make a choice whether to follow the recommendation to not specify a src attribute and thus force users of older browsers to see only the alt text, or whether we accept the fact that, in some cases, users of older browsers may end up download two images.

We decided that we'd do the latter, as we always want our users to be able to see an image. Also, as Scott mentioned in his post, one of the downsides of not using the src attribute is that your HTML then becomes invalid.

So, our final solution becomes the following, which is both a bit more conventional and concise:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Image test</title>
</head>
<body>
    <img alt="ponytailgate"
         src="images/ponytailgate_80x45.jpg"
         srcset="images/ponytailgate_1240x698.jpg 1024w,
                 images/ponytailgate_620x349.jpg   620w,
                 images/ponytailgate_320x180.jpg   320w,
                 images/ponytailgate_160x90.jpg    160w,
                 images/ponytailgate_80x45.jpg      80w"
         sizes="(min-width: 620px) 620px,
                (min-width: 320px) 320px,
                (min-width: 160px) 160px,
                (min-width: 80px)   80px" />

It does help ease the pain a bit know that we're implementing this in a site that will be targeted at mobile users (most of whom would soon have a browser that does support srcset), and that it will be some time before we build our site out to desktop users; hopefully by the time we start targeting desktop users, many of them will be using browsers with srcsetsupport.

Blog Logo

Jason Darwin


Published

Image

Making Stuff

Fairfax Media NZ Product Tech: coding at the cutting edge of media

Back to Overview