Loading

¿Quién no ha tenido problemas intentando que el sitio no se viera mientras se cargaba el contenido? Eso mismo ocurrió en mi última web. El diseño poseía una gran cantidad de imágenes en cada sección, con fotos imposible de optimizar por su naturaleza, lo que provocando un efecto poco elegante en cada cambio de página: el diseño se entremezclaba hasta que las imágenes se dignaban a descargarse. ¿La solución? Entre muchas posibilidades decidí crear un cargador que tapara todo el sitio hasta estuviera preparado para desfilar por los ojos de mis visitantes.

Por la red vi muchos snippets, o códigos, que podían solucionarlos; pero la gran mayoría desactualizados. Por ello mismo decidí programar un sistema moderno que comparto para que cualquiera pueda usarlo.

Ejemplo

Código o snippet

Es muy importante que el HTML y CSS del Cargador sea lo primero que vea el usuario, incluso antes de que el archivo CSS con tus estilos lleguen a procesarse. Por ello deberás incluirlo en crudo, y además donde empiece body. En el ejempo te dejo una maquetación donde se cubre todo lo visible, añade un fondo blanco y por otro lado centra un spin (circulito que da vueltas).

<body>
    <!-- Loading -->
    <style>
        .loading {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: white;
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 9999;
            transition: 1s all;
            opacity: 0;
        }
        .loading.show {
            opacity: 1;
        }
        .loading .spin {
            border: 3px solid hsla(185, 100%, 62%, 0.2);
            border-top-color: #3cefff;
            border-radius: 50%;
            width: 3em;
            height: 3em;
            animation: spin 1s linear infinite;
        }
        @keyframes spin {
          to {
            transform: rotate(360deg);
          }
        }            
    </style>
    <div class="loading show">
        <div class="spin"></div>
    </div>

    <!--- Resto de tu HTML -->
</body>

Ahora que esperar cuando sea necesario. El siguiente código elimina el loading cuando:

  • El DOM esta listo (HTML).
  • Se ha descargado todas las imágenes.
  • Esta presente el HTML del cargador (representado con la clase loading).
//======================================================================
// LOADING
//======================================================================
var Loading = (loadingDelayHidden = 0) => {

    //-----------------------------------------------------
    // Variables
    //-----------------------------------------------------
    // HTML
    let loading = null;
    // Retardo para borrar
    const myLoadingDelayHidden = loadingDelayHidden;
    // Imágenes
    let imgs = [];
    let lenImgs = 0;
    let counterImgsLoading = 0;

    //-----------------------------------------------------
    // Funciones
    //-----------------------------------------------------

    /**
     * Método que aumenta el contador de las imágenes cargadas
     */
    function incrementCounterImgs() {
        counterImgsLoading += 1;
        // Comprueba si todas las imágenes están cargadas
        if (counterImgsLoading === lenImgs) hideLoading();
    }

    /**
     * Ocultar HTML
     */
    function hideLoading() {
        // Comprueba que exista el HTML
        if(loading !== null) {
            // Oculta el HTML de "cargando..." quitando la clase .show
            loading.classList.remove('show');

            // Borra el HTML
            setTimeout(function () {
                loading.remove();
            }, myLoadingDelayHidden);
        }

    }

    /**
     * Método que inicia la lógica
     */
    function init() {
        /* Comprobar que el HTML esté cargadas */
        document.addEventListener('DOMContentLoaded', function () {
            loading = document.querySelector('.loading');
            imgs = Array.from(document.images);
            lenImgs = imgs.length;

            /* Comprobar que todas las imágenes estén cargadas */
            if(imgs.length === 0) {
                // No hay ninguna
                hideLoading();
            } else {
                // Una o más
                imgs.forEach(function (img) {
                    // A cada una le añade un evento que cuando se carge la imagen llame a la funcion incrementCounterImgs
                    img.addEventListener('load', incrementCounterImgs, false);
                });
            }
        });
    }

    return {
        'init': init
    }
}

// Para usarlo se declara e inicia. El número es el tiempo transcurrido para borra el HTML una vez cargado todos los elementos, en este caso 1 segundo: 1000 milisegundos,
Loading(1000).init();

Presta especial atención a esta línea.

Loading(1000).init();

Indica el retardo, en milisegundos, a la hora de borrar el cargador cuando todo esté descargado. Y init() será el encargado de activar la lógica.

Completo y optimizado

Para que puedas usarlo directamente he dejado el ejemplo con el código javascript minimizado (quitando comentarios y espacios para que ocupe menos).

<!-- Loading CSS -->
<style>
    .loading {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background-color: white;
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999;
        transition: 1s all;
        opacity: 0;
    }
    .loading.show {
        opacity: 1;
    }
    .loading .spin {
        border: 3px solid hsla(185, 100%, 62%, 0.2);
        border-top-color: #3cefff;
        border-radius: 50%;
        width: 3em;
        height: 3em;
        animation: spin 1s linear infinite;
    }
    @keyframes spin {
      to {
        transform: rotate(360deg);
      }
    }            
</style>

<!-- Loading HTML -->
<div class="loading show">
    <div class="spin"></div>
</div>

<!-- Loading Javascript -->
<script>
// Loading
var Loading=(loadingDelayHidden=0)=>{let loading=null;const myLoadingDelayHidden=loadingDelayHidden;let imgs=[];let lenImgs=0;let counterImgsLoading=0;function incrementCounterImgs(){counterImgsLoading+=1;if(counterImgsLoading===lenImgs){hideLoading()}}function hideLoading(){if(loading!==null){loading.classList.remove('show');setTimeout(function(){loading.remove()},myLoadingDelayHidden)}}function init(){document.addEventListener('DOMContentLoaded',function(){loading=document.querySelector('.loading');imgs=Array.from(document.images);lenImgs=imgs.length;if(imgs.length===0){hideLoading()}else{imgs.forEach(function(img){img.addEventListener('load',incrementCounterImgs,false)})}})}return{'init':init}}

Loading(1000).init();
</script>