Responsive images are fantastic, aren’t they?
The ability to deliver the most suitable image, both in terms of dimensions and file size, depending on the viewport (that is, the width of the browser) of any given device is one that I am very glad we have.
But what about responsive background images?
In my experience using and building for the web, the typical implementation of responsive images focuses on inline, not background images.
While there are many examples of sites that use techniques to make inline images look and behave as though they are applied as a background, more often than not the definition of a background image on the web is one that utilises the CSS background-image property along with background-size and background-position.
Now, I understand that there are occasions where making an inline image behave like a background image is desirable e.g. where having the image such as a hero header accompanying an article indexed by search engines is of critical importance.
However in general I am not a fan of forcing an inline image to behave like its background counterpart for a variety of reasons that I won’t waste time dwelling on here. If you need to force an inline image to behave like a background image, I would argue that the designs need to be re-visited.
Over the spring, I worked on a particularly image heavy build that made extensive use of background images. This project was the catalyst for me going ahead and building a simple, re-usable solution that I could use on this particular project and add to Kapow!, our in-house WordPress development boilerplate.
Implementing responsive background images is a two part process.
First, we need to write some good’ol PHP to craft a WordPress template tag that will accept an image ID and a bunch of settings at one end, and generate a list of HTML data attributes at the other containing information that we can parse and use.
Before I briefly explain and introduce you to the code for both of these component parts, there’s an elephant in the room that needs addressing…
The whole point of responsive background images, as per their inline counterparts, is to deliver the most suitable image to the device requesting it. In the case of a mobile user, delivering an 80kb image as opposed to the 800kb version results in a huge data saving which is both beneficial and responsible.
The problem is that any subsequent attempt to deliver a more suitable image, after initially setting a default background image, results in two images being downloaded by the browser for each element; both the default image and the more suitable alternative.
Two images, more data, bad monkey.
Therefore, we need to start from a position of not having any background image associated with the element(s) at all, with suitable background colours in place to keep things in line with the design, or provide the appropriate contrast should any text be present above the element e.g. a hero header on a blog article.
Then we must dynamically update the CSS
background-image property with the most suitable image available after checking our context — that is, the width of the viewport — bearing in mind that this can and will change size and orientation based on user input.
The PHP & WordPress Bit
In the GitHub Gist below you’ll find the code for the WordPress template tag I wrote to generate the data attributes on any elements that need responsive background images.
The template tag takes four arguments:
- The post (integer) of the image attachment.
- An array of image size slugs (string) such as
your-custom-sizeetc, and min-width breakpoint values (integer) in pixels e.g.
1024etc added in a mobile-first order.
- The slug of the image size you would like to use as the default fallback image e.g.
- Whether you want to echo or return the data attributes, boolean
trueto echo (default behaviour) or
Here’s the code in question, which should be added to your
functions.php or whichever file you use to store your template tags in the theme.
In terms of how you would use this in the wild, here’s another Gist showing a quick example of it in action with the assumption that we are inside The WordPress Loop:
So in this specific example, the resulting HTML markup for the
my-example-element would be as follows:
<div class="js-bg-img my-example-element" data-bg-480="http://xyz.com/wp-content/themes/example/img/img-768x320.jpg" data-bg-768="http://xyz.com/wp-content/themes/example/img/img-1024x428.jpg" data-bg-1024="http://xyz.com/wp-content/themes/example/img/img-1200x500.jpg" >
One important thing to note when you are passing image sizes and breakpoints into this template tag is that your image sizes (registered in your theme using the add_image_size() function) should be large enough to not require stretching by the time you hit the next breakpoint.
So for example, if you’re setting a breakpoint value of
480, and your next breakpoint is
768, you actually need the image size that kicks in at
480 to be
767px wide; the next breakpoint value minus one pixel.
This will ensure that the image you load at
480 doesn’t need to be stretched in any way to make it fit, which will reduce the quality of the image.
We are now done with the PHP & WordPress part of the implementation. Onwards!
The function extracts the media query breakpoint values and image URLs from the data attributes on the target elements, checks to see which images are the most appropriate for the current viewport width, and then updates the background image URLs for the elements where necessary.
The function takes a single parameter, which is a standard CSS selector such as
.js-bg-img used to target the elements that have background images which need to be responsive.
Here’s the code in question which can be enqueued in a
footer.js or similar file in the footer, as it will need to fire once the document is ready.
The function is fired on the initial page load when the document is ready, and is then called again
300ms after the viewport has stopped being resized, or when the orientation of the device is changed e.g when you change from landscape to portrait on a tablet. The throttle exists to prevent the resizing of the browser from killing the performance of your browser.
It is worth pointing out that this solution relies on Modernizr as a dependency for quick and easy viewport width checking. You could modify this approach to use
window.matchMedia() if your scope of work for the project does not include supporting legacy browsers.
A Working Example
Resize your browser window (or change your tablet from landscape to portrait etc) and each time you pause/stop, you’ll see that the background images automatically update.
I am pulling in dynamic images from FillMurray.com in this example so it is possible that you will see brief pauses before each new image is loaded due to the fact that the data is being pulled from an external source; with self-hosted images this won’t be as noticeable.
I have embedded the pen below, but if you want to view the full page version in your browser you can do so by clicking here.
This is a useful and time saving technique that I now use on all projects wherever responsive background images are needed. Feel free to use this code to make your life easier on your own projects!
Any comments? I’d love to hear from you!