Web Loading Spinner

How to Create a Loading Spinner for a Web Site with CSS and JavaScript

html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./app.js" defer></script>
    <link rel="stylesheet" href="./style.css">
    <title>Document</title>
</head>

<body>
    <div class="loader"></div>
    <h1>home page</h1>
    <h2>welcome to my website...</h2>
    <img src="https://images.unsplash.com/photo-1693574855928-68c1c8a6daee?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDE5fHx8ZW58MHx8fHx8"
        width="100">
    <img src="https://images.unsplash.com/photo-1719507523391-bd10fbe12868?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
        width="100">
    <img src="https://images.unsplash.com/photo-1729710448593-7a361fe6323f?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDE1fHx8ZW58MHx8fHx8"
        width="100">
</body>

</html>

css

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

img {
    width: 300px;
}

.loader {
    width: 100%;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    background-color: #FFFFFF;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: opacity 0.90s, visibility 0.90s;

    &::after {
        content: "";
        position: absolute;
        width: 50px;
        height: 50px;
        border: 5px solid #ececec;
        border-top-color: #5350ff;
        border-radius: 50%;
        animation: loading 0.90s cubic-bezier(.42, 0, .5, 1.23) infinite;
    }
}

.hide-loader {
    opacity: 0;
    visibility: hidden;
}

@keyframes loading {
    from {
        transform: rotate(0turn);
    }

    to {
        transform: rotate(1turn);
    }
}

javascript

window.addEventListener('load', () => {
    const loader = document.querySelector('.loader');
    if (!loader) return;

    loader.classList.add('hide-loader');

    loader.addEventListener('transitionend', () => {
        loader.remove();

    }, { once: true });

    setTimeout(() => {
        if (document.body.contains(loader)) {
            loader.remove();
        }
    }, 3000);
});