Responsive Images: a Drupal Implementation

The popularity of responsive web design is constantly exposing behaviors that web browsers have gotten away with over the years. Many of these behaviors — while brilliant for a single-screen web — become a direct hindrance when dealing with the multi-screen extravaganza that we face now.

One of the most hotly debated topics is responsive images. This was a topic widely exposed by Filament Group due to their work on the Boston Globe, and it continues to be an issue for every bandwidth-conscious site today.

Update 2013-10-28: The possibility we mentioned this post has come true. The <picture> technique outlined in this blog post has been replaced by several competing ideas (and might be published as a Note rather than a Recommendation). The most notable alternative is src-N which is even more appealing when combined with a new HTTP header being proposed, called Client Hints. We encourage you to do diligent research before implementing responsive images long-term on a project, and make sure you’ll have the ability to support the option you choose for the lifetime of the project.

Update 2014-03-18: Life on the bleeding edge, eh? Picture is back on the table, with multiple vendors moving to implement. Stay updated by visiting http://responsiveimages.org

History

The foundations of this topic have been hotly debated and oft explored in the past year, so here’s a list of articles that capture the history of responsive images and demonstrate the challenges developers face on a modern site:

  • Mat Marquis, part of Filament Group and the Boston Globe team, took it upon himself to take the helm of this issue, writing about the initial challenges and creating the Responsive Images Community Group. The group has proposed a solution and is busy solidifying a web standard for responsive images, backed by the trial and error of developers worldwide.
  • Jason Grigsby has written extensively about responsive image techniques, deftly balancing the need for simplicity on the authors’ side, while recognizing the underlying tech issues browsers inadvertently (and rightfully) created during our beloved single-screen golden era.
  • Robert Paul Lloyd writes about how no solution is ideal, suggesting that we go back to the drawing board and create an entirely new image format. In the long term this is pretty likely. For certain types of imagery a bandwidth-cheap, scalable format already exists in SVG, icon fonts, and other vector formats. A similar vessel needs to exist for photos too.

Today’s solution

Whatever the final outcome of the standards process, if you find yourself needing responsive images today there are several approaches, the most successful of which is currently the <picture> element.

In a nutshell, <picture> is a brand new element with behavior that is — for now — controlled by JavaScript. This allows us to achieve all of the goals for a proper responsive image request: avoiding image prefetching, preferring author-controlled image selection, and ultimately only downloading a single image (instead of a fallback plus larger version)

Picturefill is its own open-source library, available on Github.

Implementing responsive images on a Drupal site

The latest responsive site that Four Kitchens launched, Full Plate Living, tightly integrates responsive images with Drupal content. The methods for doing so are thankfully rather easy, but as with all things Drupal there is a bit of a learning curve to get started. Responsive images can be added to content, views, etc. with the help of two contributed modules: Breakpoints and Picture. These two modules rely on Drupal’s core Image Styles module to output images in various sizes using a URL-specific, render-on-demand system.

Configuring breakpoints

In responsive web design breakpoints are used with media queries to determine when new CSS rules should apply to the site’s markup. As its name suggests, the Breakpoints module allows your site to define media queries on which you’d like to take action. The module provides a canonical list of breakpoints that are accessible from the database and thus surfaced to your site’s code. The Breakpoints module also has the notion of a “breakpoints group.” Groups are particularly useful for defining sets of breakpoints that are only relevant to certain parts of the site. These breakpoints can then be semantically referenced by their group name which allows you to reuse breakpoint names between groups, even if the media queries aren’t the same.

In the case of Full Plate Living we had one global set of breakpoints that was defined in the theme’s .info file:

breakpoints[smartphone] = (min-width: 320px)
breakpoints[fourhundred] = (min-width: 415px)
breakpoints[smartphone_only] = (min-width: 320px) and (max-width: 767px)
breakpoints[smartphone_landscape] = (min-width: 480px)
breakpoints[smartphone_landscape_only] = (min-width: 480px) and (max-width: 767px)
breakpoints[small_menu] = (min-width: 430px)
breakpoints[smaller_menu] = (min-width: 421px)
breakpoints[recipes_landing] = (min-wdith: 520px)
breakpoints[user_reg] = (min-width: 625px)
breakpoints[tablet] = (min-width: 768px)
breakpoints[tablet_only] = (min-width: 768px) and (max-width: 979px)
breakpoints[desktop] = (min-width: 980px)

This same set of breakpoints was used in our Sass and JavaScript files (with response.js) to provide a consistent list of breakpoints for all of our front end code to interact with. Unfortunately this list was duplicated in the three places; a future implementation might use a build tool like grunt to keep the global breakpoints list in one place and update the .info, Sass, and JavaScript definitions appropriately.

Additional breakpoint groups were added for content types so that the amount of markup required for responsive images could be kept down (one breakpoint means two picture options: the default, and the one defined for the breakpoint).

Configuring image styles

Core’s Image Styles are used to format the images that will be used in the picture element. It’s a good idea to give the image styles meaningful names so that configuring the Picture module is more straightforward. In the case of Full Plate Living we generally used two image styles per page: STYLE__full for images delivered to large viewports, and STYLE__mobile for images delivered to small viewports.

Configuring Picture

The Picture module ties information from Breakpoints and Image Styles together and ultimately provides the markup and picturefill JavaScript that will be used on the page. Each breakpoint group will have a tab on the Picture admin page that lists its breakpoints and provides a dropdown for each one to specify the image style that should be used.

Configuration UI for breakpoints within Picture module

Finally, when you’re defining the display style for your image fields you will choose “Picture” as the formatter for the image. The settings for this field will allow you to choose the “picture group” and a “fallback” image style. The fallback image style will be used if no breakpoint conditions are met. If you’re building mobile-first, this would be your base mobile style definition and should be the smallest image that will be delivered to the client.

Configuration UI for Picture image formatter

Show me the data

To demonstrate the advantages of the <picture> element we captured data from the Full Plate Living recipe landing page. See those beautiful, gigantic images below the search? Such a huge image is not needed for the same effect on a small screen. Implementing <picture> resulted in a difference of 157K out of a max page weight of 746K. Here are the two network waterfalls:

Mobile

Network waterfall for Full Plate Living taken from a small screen. The statistic of interest is a set of three content images whose default state causes their file sizes to be 15, 15, and 10 kilobytes.

The three images in this screenshot that start with 2012 are the mobile-formatted images. They total approximately 40K at the default breakpoint.

Desktop

Network waterfall for Full Plate Living taken from a laptop. The statistic of interest is a set of three content images whose JavaScript-altered state causes their file sizes to be 74, 47, and 76 kilobytes.

Looking again at those images with the same 2012 prefix, we see a total of 197K, meaning we are preventing the site from serving mobile users with approximately 157K of data that they don’t need.

You can see that the download “initiator” for the images is a script — not the HTML page — due to the picturefill script modifying the DOM and specifying the image that should be used. This DOM modification causes the markup on the page to differ based on the viewport, visible in this gist.

Div + data-attributes

The <picture> element was used on Full Plate Living, but for now it’s considered slightly more future-proof to use <div> elements with data attributes.

<div data-picture data-alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
    <div data-src="small.jpg"></div>
    <div data-src="medium.jpg"     data-media="(min-width: 400px)"></div>
    <div data-src="large.jpg"      data-media="(min-width: 800px)"></div>
    <div data-src="extralarge.jpg" data-media="(min-width: 1000px)"></div>
 
    <!-- Fallback content for non-JS browsers. Same img src as the initial, unqualified source element. -->
    <noscript>
        <img src="external/imgs/small.jpg" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
    </noscript>
</div>

The picturefill script and Picture module both currently use the <div> method, so although your markup will look different, the end result will be the same.

In conclusion

We all recognize the need for a responsive image container on the web. Today’s solution might look very different from tomorrow’s, but the need for device-optimized media will continue to grow as fast as the variety of devices accessing the web. Just hang on, remember to test, and enjoy the ride!

Credits: this article was co-written by Elliott Foster.

Chris Ruppel is a frontend developer who makes websites load fast and shrink on your phone. Although he’s a native Texan, Chris currently lives in the beautiful town of Freiburg, Germany

Commenting on this Blog post is closed.

Comments

We originally started with one of the adaptive image projects (I don’t think it was the one you’ve referenced) for Full Plate Living but had issues with caching. Specifically when pages were cached by varnish, whatever image ended up in the markup stayed there until the cache was cleared. It worked great on a cold cache though!

Chris might be able to correct me if I’m wrong, but I believe the method used by the picture module is the one that will likely be used for Drupal 8.

Can I link your post on the picture diocese page?

Regarding the markup, what does it generate when I want a link on my image? I can’t place an <a> around a <div>, so how would this work?

Technically you can place an <a> around a <div> — it’s just not 100% valid markup. I’d say in this case, if you’re using experimental markup like <picture> you get a free pass if you want to wrap a block-level element in a link.

(I tweaked the code in your original comment and removed the other corrective comments, please pardon our markdown filter!)