Responsive Background Images with WordPress

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.

The Solution

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.

Second, we need some JavaScript to look for these data attributes, parse the data and then update the CSS for a given element or collection of elements. This update involves applying the most appropriate background image for the current viewport width, using the image URL stored in one of those attributes to replace the current URL.

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…

Yes, this solution relies on JavaScript

One of the problems inherent with this kind of solution is that JavaScript is a mandatory requirement, and therefore goes against the wonderful principles of progressive enhancement that I do my utmost to adhere to. If JavaScript is disabled or broken in the browser, this won’t work.

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.

However, web browsers parse and render the HTML & CSS of a web page in a way that means background image assets are downloaded straight away as soon as the stylesheet has loaded, regardless of the viewport/device context. As we can’t intercept this with JavaScript, we have a problem.

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:

  1. The post  (integer) of the image attachment.
  2. An array of image size slugs (string) such as medium, large, your-custom-size etc, and min-width breakpoint values (integer) in pixels e.g. 480, 768, 1024 etc added in a mobile-first order.
  3. The slug of the image size you would like to use as the default fallback image e.g. large.
  4. Whether you want to echo or return the data attributes, boolean true to echo (default behaviour) or false to return.

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:

 class="js-bg-img my-example-element"

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 JavaScript & CSS Bit

In the GitHub Gist below you’ll find the JavaScript function and associated event listener that I wrote

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

To demonstrate responsive background images, I’ve put together a CodePen with some example HTML markup as it would be generated by the WordPress template tag, along with the JavaScript to handle the actual task of changing the images.

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 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.

[codepen_embed height=”265″ theme_id=”0″ slug_hash=”NgyVeE” default_tab=”js,result” user=”davetgreen” preview=”true” data-preview=”true”]See the Pen Responsive Background Images by davetgreen (@davetgreen) on CodePen.[/codepen_embed]

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!

Add a new VVV development site just for WooCommerce

I’ve spent the last couple of weeks carrying out a number of updates to Kapow!, our in-house WordPress development boilerplate that we use at Make Do as a starting point for all new client sites, and as a result of this I’ve had to upgrade my local set-up to use the super-shiny brand new Varying Vagrant Vagrants (VVV) 2.0.

VVV makes the process of provisioning new local development sites a breeze, and I decided to take the opportunity to create a new local environment for WooCommerce plugin/theme development, testing and general tinkering.

Granted, I already have the wordpress-default site available, but I’m keen to keep that for building and testing vanilla themes and plugins: so the goal is to have two separate environments.

Forking the default provision script

VVV 2.0 pulls down a couple of GitHub repositories containing the provisioning scripts necessary to install the default wordpress-default and wordpress-develop sites when you run a complete provision: such as when you install or upgrade VVV.

The beauty of this is that the default site repositories can easily be forked and modified for our own use. I’ve forked the repository that is responsible for setting up the wordpress-default site and have modified it to change the local domain to, change the database to wordpress_woocommere and install the WooCommerce plugin using WP CLI, amongst other small tweaks. You can find the fork here: VVV WordPress WooCommerce

Adding the new site configuration

In your vvv-custom.yml file you should add the new WooCommerce site directly below your wordpress-default site configuration. Here’s how my file looks:

As you can see from the above Gist, in the new site configuration that I’ve called wordpress-default-woo I’m pointing to my fork of the default site repository, rather than the VVV version. You can call this site configuration anything you like, as long as it remains in the same format e.g. your-site-slug.

Provisioning the new site

One of the things I love the most about VVV 2.0 is the ability to provision a single site at a time, rather than having to endure the full provisioning process.

First of all ensure that you’re in your root VVV folder (mine is ~/Vagrant for example) and then execute the following command to provision the new WooCommerce development site, replacing wordpress-default-woo with the site slug that you’ve chosen:

vagrant provision --provision-with=site-wordpress-default-woo

A couple of minutes later you should see something like this:

Huzzah! As you can see from the output of the provisioning script, you will not only have a default copy of WordPress installed and configured, but you will have the latest stable release of WooCommerce installed and activated.

Now, if you visit in your browser and you were fortunate enough to experience no issues during the provisioning process you should be treated to this.

Now you have a totally separate WordPress environment complete with WooCommerce!

UPDATE: I’ve now tweaked the provisioning script to automatically install and activate the Storefront theme as well, providing a more appropriate base theme to work with.

Enqueuing JS for legacy browsers, the WordPress way

One of the things I love about being a WordPress developer is the ongoing discovery of core functions that make my life easier, or empower me to implement more best practice in my code.

At Make Do one of my chief internal responsibilities as front-end lead is managing our workflow boilerplate Kapow! which we use as a basis for all new WordPress projects.

In the theme component of Kapow! I’ve been happily adding a script to header.php the old fashioned way, which contains various poly-fills and shims to provide enhanced out-of-the-box support for legacy IE versions 7 & 8.

<!--[if lt IE 9]>  ?php%20echo%20esc_url(%20get_stylesheet_directory_uri()%20);%20?/assets/js/header_ie.min.js <![endif]-->

Normally I would rely on WordPress core’s wp_register_script() and/or wp_enqueue_script() functions when introducing JS or CSS assets into a theme to follow best practice, however in this case the need for conditional comments has meant that I’ve had to stick with the old fashioned way. Until this week…

Enter wp_script_add_data() ! This function exists for adding metadata to a script. It accepts three arguments: handle, key and value. You can find the function documentation on the Code Reference. Another gem that I had absolutely no idea about!

The handle is the unique ID you assign to the script when registering and/or enqueuing e.g. legacy_ie.

The key relates to the type of metadata you’re adding and from what I can see conditional is the only documented value available for use. This tells WordPress that the script in question should be enclosed within a conditional comment.

Finally, the value is the content (in this case at least) of the conditional itself e.g. lt IE 9 to detect all versions of IE lower than 9.

This meant I could remove the script from header.php and add the script The WordPress Way as shown in the Gist below.

As you can see we enqueue the script (no need to register unless it’s a dependency that needs to be referenced elsewhere) and then add our script meta to introduce the conditional comments before hooking into wp_enqueue_scripts to invoke the function.

The script will then be added to the header rather than the footer as the wp_enqueue_script() parameter $in_footer defaults to false if not supplied.

And there you have it, a way to introduce scripts wrapped in conditional comments into your theme without polluting your template files.

You truly do learn something new every day!