Responsive Background Images Using Blade Components

You’ll probably agree that using the same background image for a desktop screen as well as for a mobile device is not good for performance. And to make matters worse usually full viewport background image is the main above the fold element of most home pages.

Wouldn’t be nice if we had the same responsive image functionality for our background images as we have for img tags?

Well, not long ago I found a neat trick how to do just that. I’ll show you how to automate creating responsive background images so that all you’re left to do is upload one high-resolution image to WordPress and pass its ID to a Blade component.

Current options for responsive background images

The srcset and sizes attributes for img tags have been for around for a while now. According to Can I Use browser support is about 89%.

For background-image set with CSS the similar standard would be image-set() function. But the problem is that there is no support for Firefox and Edge. It could be a good alternative in the future but for now, I’d not recommend using image-set for responsive background images.

Another option is the object-fit CSS property for img tags but again browser support is lacking, and if you need to support IE then it’s off the table.

Alternative approach

WordPress will take care of generating different image sizes, including your custom ones. What we are left to do is to make sure that the browser downloads the right size of an image.

We can use the power of the img tag with srcset and sizes attributes to pick the appropriate image size.

Once the image is loaded then with a little bit of JavaScript we’ll apply it to the background of an element that has our predefined class.

We’ll also use Blade’s component to create a background image container.

JavaScript snippet

In this case, our background images will depend on JavaScript being supported by all browsers.

If you’re fine with that then here is the JavaScript code snippet that does all the magic.

// Search for inner img, wait for load event and grab src to apply as background-image
export class ResponsiveBackgroundImage {
  constructor(element) {
    this.element = element;
    this.img = element.querySelector('img');
    this.src = '';
    this.img.addEventListener('load', () => {
      this.update();
    });
    if (this.img.complete) {
      this.update();
    }
  }
  update() {
    let src = typeof this.img.currentSrc !== 'undefined' ? this.img.currentSrc : this.img.src;
    if (this.src !== src) {
      this.src = src;
      this.element.style.backgroundImage = 'url("' + this.src + '")';
    }
  }
}

// Init to look for containers with .js-bg-image class
const bgImages = document.querySelectorAll('.js-bg-image');
for (let i = 0; i < bgImages.length; i++) {
  new ResponsiveBackgroundImage(bgImages[i]);
}

Let’s place it in scripts/respbgimages.js and include in resources/assets/config.json:

...
"entry": {
  "main": [
    "./scripts/main.js",
    "./styles/main.scss"
  ],
  "customizer": [
    "./scripts/customizer.js"
  ],
  "respbgimages": [
    "./scripts/respbgimages.js"
  ]
},
...

We want this script to start executing as soon as possible once our page is loaded with all img tags so let’s enqueue it in the footer before sage/main.js.

wp_enqueue_script('respbgimages', asset_path('scripts/respbgimages.js'), [], null, true);

Blade components

Components in Blade are very similar in behavior to views.

Let’s create our background image component in views/components/bg-image.blade.php.

<section>
  {!! $slot !!}
</section>

When we include a component in Blade template the $slot variable will be replaced with a markup that’s inside a component. Similarly like @yield('content') in layouts/app.blade.php is replaced by the content inside @section('content') @endsection in Sage templates.

Here is the full markup for a component for a full-width background image.

<section class="c-bg-image {{$class ?? ''}} js-bg-image">
  <img src="{{ wp_get_attachment_image_src($image, 'full')[0] }}" style="display:none" sizes="100vw" srcset="{{ wp_get_attachment_image_srcset($image, 'full') }}">
  {!! $slot !!}
</section>

I’m setting a container to which background image will be applied and an img inside it to load the correct image size. If your website has a boxed design then adjust sizes attribute to something like that:

sizes="(min-width: 1400px) 1400px, 100vw"

Also, you can pass an optional $class variable in case you need to style a specific background image.

Don’t get alarmed by display: none in the img, a browser will still grab the correct src from a srcset. As the proof, I made the fiddle demonstration.

Finally, include a component in your template:

@component('bg-image, ['image' => $id])
  <div class="container">
    <h2>Title</h2>
    <p>Some text</p>
  </div>
@endcomponent

Bonus tip

Also, while a full-size image is loading, as a fallback we can use background-image: linear-gradient() reflecting your background image colors to improve a perceived load time. Here is a quick guide from Harry Roberts how he does it for his own site.

Join the discussion on Roots Discourse

Help support our open-source development efforts

Help grow Roots

Join over 6,000 subscribers on our newsletter to get the latest Roots updates, along with occasional tips on building better WordPress sites.

Looking for WordPress plugin recommendations, the newest modern WordPress projects, and general web development tips and articles?

“Easily the best WordPress email I get.” Colin OBrien

Follow us on Twitter @rootswp

Ready to checkout?