Search code examples
javascripthtmlcssimageloading

Loading animation disappears before loading is complete


I am trying to show a loading animation while my page loads, but my animation disappears before the loading is complete. The page consists of just 10 random images from source.unsplash.com. The idea is to use them as background images, changing the image being displayed every 3 seconds.

In the first second of loading the page, several different images are quickly shown, then the page settles into the expected behavior of having a changing background every 3 seconds. As a solution, I made a function that iterates through the NodeList of images, making sure that each image has loaded using onload. After this, I then remove the loading animation. However, the animation does not prevent the first second of several different images being quickly shown, which is the whole point of having the loading animation.

Is there a way to hide my content until everything has loaded properly? I have tried setting the z-index of the first image (id=0) to be 1, while setting the z-index of all other images to 0 so that only the first image is being displayed initially, but that only works if the first image loads before all other images. That is not always the case. I could hardcode the animation to last a few seconds but that doesn't strike me as a good solution at all. Any advice would be greatly appreciated!

// function to rotate which li background image is being displayed
function changeIndex(obj, coffeeShops) {

    if (obj.num === 0) {
        coffeeShops[coffeeShops.length - 1].style.zIndex = 0;
    }
    else {
        coffeeShops[obj.num - 1].style.zIndex = 0;
    }
    coffeeShops[obj.num].style.zIndex = 1;

    obj.num++;
    if (obj.num === coffeeShops.length) {
        obj.num = 0;
    }
};

function changeBg(t) {
    const coffeeShops = document.querySelectorAll('img');
    let obj = {};
    obj.num = 0;

    let timerId = setTimeout(function change() {
        changeIndex(obj, coffeeShops);
        timerId = setTimeout(change, t * 1000);
    }, t * 1000);
};

function loadPage() {
    const images = document.querySelectorAll('.load');
    
    images.forEach(image => {
        image.onload = function () {
            image.classList.remove('load');
        };
    });

    const loader = document.querySelector('.loader-wrapper');
    loader.remove();
};



loadPage();
changeBg(3);
.loader-wrapper {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    background-color: #242f3f;
    display:flex;
    justify-content: center;
    align-items: center;
}
.loader {
    display: inline-block;
    width: 30px;
    height: 30px;
    position: relative;
    border: 4px solid #Fff;
    animation: loader 2s infinite ease;
}
.loader-inner {
    vertical-align: top;
    display: inline-block;
    width: 100%;
    background-color: #fff;
    animation: loader-inner 2s infinite ease-in;
}
@keyframes loader {
    0% { transform: rotate(0deg);}
    25% { transform: rotate(180deg);}
    50% { transform: rotate(180deg);}
    75% { transform: rotate(360deg);}
    100% { transform: rotate(360deg);}
}
@keyframes loader-inner {
    0% { height: 0%;}
    25% { height: 0%;}
    50% { height: 100%;}
    75% { height: 100%;}
    100% { height: 0%;}
}

img {
    width: 100%;
    margin: 0;
    padding: 0;
    position: absolute;
    top: 0;
    left: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Home</title>
    <link rel="preload" href="https://source.unsplash.com/collection/62334021/1920x1080" as="image">
    <link rel="stylesheet" href="home.css">
</head>

<body>

    <div class="pickgradient">
        <img class="load" src="https://source.unsplash.com/collection/62334021/1920x1080" id="0">
        <img class="load" src="https://source.unsplash.com/collection/8331835/1920x1080" id="1">
        <img class="load" src="https://source.unsplash.com/collection/584433/1920x1080" id="2">
        <img class="load" src="https://source.unsplash.com/collection/9787713/1920x1080" id="3">
        <img class="load" src="https://source.unsplash.com/collection/11288659/1920x1080" id="4">
        <img class="load" src="https://source.unsplash.com/collection/5045180/1920x1080" id="5">
        <img class="load" src="https://source.unsplash.com/collection/4794086/1920x1080" id="6">
        <img class="load" src="https://source.unsplash.com/collection/40914537/1920x1080" id="7">
        <img class="load" src="https://source.unsplash.com/collection/1625008/1920x1080" id="8">
        <img class="load" src="https://source.unsplash.com/collection/2248881/1920x1080" id="9">
    </div>

    <div class="loader-wrapper">
        <span class="loader"><span class="loader-inner"></span></span>
    </div>

    <script src="home.js">
    </script>
</body>

</html>


Solution

    1. I not sure what your onload function does. Its removed the load class, but there is no style applied to this class, so you change nothing.
    2. Whiy do not use 'display' or 'opacity' styles insead z-index so not related images will not shown at all,not just covered.
    3. For the loading screen - probably you want to show i untilfirst image loads, also probably you want to start the slider timeout then.

    Result:

    // function to rotate which li background image is being displayed
    function changeIndex(obj, coffeeShops) {
    
        coffeeShops.forEach((img,i) => img.style.display = obj.num === i ? 'block':'none');
        obj.num++;
        if (obj.num === coffeeShops.length) {
            obj.num = 0;
        }
    };
    
    function changeBg(t) {
        const coffeeShops = document.querySelectorAll('img');
        let obj = {};
        obj.num = 0;
    
        let timerId = setTimeout(function change() {
            changeIndex(obj, coffeeShops);
            timerId = setTimeout(change, t * 1000);
        }, t * 1000);
    };
    
    function loadPage() {
        const images = document.querySelectorAll('.load');
        
        images[0].onload = () => {
            const loader = document.querySelector('.loader-wrapper');
            loader.remove();
            changeBg(3);
        };
    };
    
    
    
    loadPage();
    .loader-wrapper {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0;
        left: 0;
        background-color: #242f3f;
        display:flex;
        justify-content: center;
        align-items: center;
    }
    .loader {
        display: inline-block;
        width: 30px;
        height: 30px;
        position: relative;
        border: 4px solid #Fff;
        animation: loader 2s infinite ease;
    }
    .loader-inner {
        vertical-align: top;
        display: inline-block;
        width: 100%;
        background-color: #fff;
        animation: loader-inner 2s infinite ease-in;
    }
    @keyframes loader {
        0% { transform: rotate(0deg);}
        25% { transform: rotate(180deg);}
        50% { transform: rotate(180deg);}
        75% { transform: rotate(360deg);}
        100% { transform: rotate(360deg);}
    }
    @keyframes loader-inner {
        0% { height: 0%;}
        25% { height: 0%;}
        50% { height: 100%;}
        75% { height: 100%;}
        100% { height: 0%;}
    }
    
    img {
        width: 100%;
        margin: 0;
        padding: 0;
        position: absolute;
        top: 0;
        left: 0;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Home</title>
        <link rel="preload" href="https://source.unsplash.com/collection/62334021/1920x1080" as="image">
        <link rel="stylesheet" href="home.css">
    </head>
    
    <body>
    
        <div class="pickgradient">
            <img class="load" src="https://source.unsplash.com/collection/62334021/1920x1080" id="0">
            <img class="load" src="https://source.unsplash.com/collection/8331835/1920x1080" id="1">
            <img class="load" src="https://source.unsplash.com/collection/584433/1920x1080" id="2">
            <img class="load" src="https://source.unsplash.com/collection/9787713/1920x1080" id="3">
            <img class="load" src="https://source.unsplash.com/collection/11288659/1920x1080" id="4">
            <img class="load" src="https://source.unsplash.com/collection/5045180/1920x1080" id="5">
            <img class="load" src="https://source.unsplash.com/collection/4794086/1920x1080" id="6">
            <img class="load" src="https://source.unsplash.com/collection/40914537/1920x1080" id="7">
            <img class="load" src="https://source.unsplash.com/collection/1625008/1920x1080" id="8">
            <img class="load" src="https://source.unsplash.com/collection/2248881/1920x1080" id="9">
        </div>
    
        <div class="loader-wrapper">
            <span class="loader"><span class="loader-inner"></span></span>
        </div>
    
        <script src="home.js">
        </script>
    </body>
    
    </html>