Preloading CSS background images with javascript

A vanilla JS script I wrote to preload background images and trigger a callback function once loaded into the DOM.

Last updated on 19 August, 2018, 1:33pm by keston

Preface

UPDATE: 19/8/18 - I've added a condition to the getAllBackgroundImages function to display console errors for any missing background images, while your developing - to help speed up debugging.

 

This is a script I wrote to create a standard 'load' event for image assets implemented as background images via CSS. The script essentially looks for html elements with a 'preload' class (which you include on relevant elements), saves query results in an array and outputs each element in a hidden container in the DOM in a img tag - so we can listen for the img load event.

 

I currently use this script to check that banner assets have fully loaded before triggering main animation. 

The Javascript
                        

function imageBgPreload(onComplete) {
    
    // preload all background images
    try {
        runBgPreload(onComplete); 
        console.log("preload try successful");
    }
    catch(err) {
        console.log("preload skipped");
        onComplete();
    }
    
        function runBgPreload(onComplete) {
        var imageHolder = document.createElement("div");
        imageHolder.setAttribute("id", "preBgHolder");
        imageHolder.style.display = "none";
        document.getElementsByTagName("body")[0].appendChild(imageHolder);
        var preloads = document.getElementsByClassName("preload");
        var imageBank = document.getElementById("preBgHolder");
        var preloadUrls = [];
        var images = [];
        var pre = [];
        var preStatus = [];
        var allImagesReady;
        var onCompleteFired = false;
        // grab all background images from CSS and preload in a CSS hidden div called preBgHolder.
        function getAllBackgroundImages() {
            for (i = 0; i < preloads.length; i++) {
                    
                    if (window.getComputedStyle(preloads[i]).getPropertyValue("background-image") != "none") {
                        preloadUrls[i] = window.getComputedStyle(preloads[i]).getPropertyValue("background-image");
                    preloadUrls[i] = preloadUrls[i].replace(/\"/g, ''); // removes url quotes as computed different in safari
                    preloadUrls[i] = preloadUrls[i].substring(4, preloadUrls[i].length - 1);
                    images[i] = new Image();
                    images[i].src = preloadUrls[i];
                    images[i].classList.add("preBg");
                    imageBank.appendChild(images[i]);      
                    } else {
                        console.error( "#" + preloads[i].id + " does not contain a background image");
                    }
            }
        }
        // check each img tag in the hidden div has loaded
        function statusListeners() {
            pre = document.getElementsByClassName("preBg");
            for (i = 0; i < pre.length; i++) {
                pre[i].addEventListener("load", checkEachStatus, false);
                preStatus[i] = pre[i].complete;
                //console.log([i] + " load status: " + preStatus[i]);
            }
        }

        function checkEachStatus() {
            //console.log("checkEachStatus()");
            function imageLoadedTrue(loadStatuses) {
                return loadStatuses == true;
            }
            for (i = 0; i < pre.length; i++) {
                preStatus[i] = pre[i].complete;
                //console.log(pre[i].complete + i);
                allImagesReady = preStatus.every(imageLoadedTrue);
                if (allImagesReady == true && onCompleteFired == false) {
                    // mainFired used to stop runMain firing more than once if images load from cache
                    //console.log("onComplete()");
                    onComplete();
                    onCompleteFired = true;
                }
            }
        };
        getAllBackgroundImages();
        statusListeners();
        // if there are no preloads to work with run the fallack function anyway
        if (preloads.length == 0) {
            onComplete();
            console.log("there was nothing to preload");
        }
    }   
}

The HTML
                        

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="utf-8">
 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
 <title >Check whether background images have loaded </title>
 <meta name="description" content="">
 <meta name="viewport" content="width=device-width">
 <link rel="stylesheet" href="styles.css">

 <style>
    
 </style>
 </head>
     <body>
         
          <div id="mainContent">
             <div id="image1" class="preload"> </div>
             <div id="image2" class="preload"> </div>
             <div id="image3" class="preload"> </div>
             <div id="image4" class="preload"> </div>
          </div>

 <script src="bgPreload.js"> </script>

 <script>
    function onceLoaded(){
        // this callback function could be a script from any other file etc
        //console.log("onceLoaded fired");
        var mainContent = document.getElementById("mainContent");     
        mainContent.style.opacity = 1;
        mainContent.style.visibility = "visible";
        mainContent.style.top = "50px";
    }
    
    imageBgPreload(onceLoaded);
 </script>
 </body>
 </html>