Web - An alternative to using image-set with background in CSS with a bit of Javascript and built-in lazy-load

I wanted to make my website score a little bit better on Google pagespeed and one area was the size of my images. I use background images for the top banners on my site and I figured I could use image-set together with the background property. However the support for image-set is partial in webkit browsers:

can-i-use-image-set

I did not like the red and yellowish colour for most browsers and only had full support for Firefox, but I also did not want to rewrite the HTML I had using an <img> tag. So I decided to add some javascript to make sure this works cross browser. I had previously written a post on how to lazy load images and decided to extend on this, so here is how you can have multiple image sizes for the css background property with a bit of javascript:

var initVisibleBackgrounds = function(){
	var currentScroll = document.scrollingElement.scrollTop;
	var elements = document.querySelectorAll('[lazy-load-background]');

	for (var i = 0; i < elements.length; i++) {
		var element = elements[i];
		if (currentScroll > element.getBoundingClientRect().top - 150) {
			var background = element.getAttribute('lazy-load-background');
            //Add the different sizes you want
			var tabletBackground = element.getAttribute('lazy-load-background-tablet');
			var phoneBackground = element.getAttribute('lazy-load-background-phone');

			var screenWidth = window.innerWidth;
			if (phoneBackground && screenWidth <= 800) {
				element.style.backgroundImage = "url('" + phoneBackground + "')";
			} else if (tabletBackground && screenWidth <= 1400) {
				element.style.backgroundImage = "url('" + tabletBackground + "')";
			}
			else {
				element.style.backgroundImage = "url('" + background + "')";
			}

			element.removeAttribute('lazy-load-background');
			element.setAttribute('lazy-loaded-background', '');
		}
	}
};

var elements = document.querySelectorAll('[lazy-load-background]');
if (elements === null || elements.length === 0)
	return;

domContentLoaded.load(function () {
	initVisibleBackgrounds();
});

window.addEventListener('scroll', function (e) {
	initVisibleBackgrounds();
}, false);

This might seem like a lot of code but it is quite straightforward. The code looks for elements with the attribute lazy-load-background if there are any close to the viewport on initial load or on scroll it lazy loads them. The extension from my previous post is that it takes a small image if the viewport width is smaller than 800px and a medium one if it is smaller than 1400px. These are taken from the attributes lazy-load-background-phone or lazy-load-background-tablet. The HTML will look like the following before the script has run:

<header lazy-load-background="/images/full-size.webp"
   lazy-load-background-tablet="/images/tablet-size.webp" 
   lazy-load-background-phone="/images/phone-size.webp">
</header>

After the script has run with a viewport larger than 1200px:
<header lazy-loaded-background="" 
   lazy-load-background-tablet="/images/tablet-size.webp" 
   lazy-load-background-phone="/images/phone-size.webp"
   style="background-image: url('/images/full-size.webp)';">
</header>

Had the viewport been smaller than 1400px and above 800px it would have taken the tablet image. Had it been below 800px it would have taken the phone size, else the fallback is the full sized image.

You can see I remove the lazy-load-background property and replace it with lazy-loaded-background so that it can easily be seen that the image was lazy loaded. There is nothing more to it, you will likely want to adjust the above to fit the sizes you use and you may have more breaking points than full, tablet and phone sized images. These are the ones I use for now, you may not agree with the sizes either!

I hope you found this helpful, feel free to leave a comment down below!