En este tutorial enseñaremos las pautas a seguir para las carga diferida de imágenes y videos, comúnmente llamado imágenes perezosas o carga de imágenes lentas. Si tu sitio Web contiene una gran cantidad de imágenes y videos, pero no deseas reducir ese contenido, la carga diferida puede ser la técnica que te ayudada a cargar ese contenido en el momento en que son necesarios.
La carga diferida es una solución que reduce el tiempo de carga inicial de la página y el tiempo de carga, pero no escatima en contenido.

¿Qué es la carga diferida? 6n1s42


La carga diferida es una técnica que aplaza la carga de recursos no esenciales en el tiempo de carga de la página. Estos recursos no esenciales se cargan en el momento en que son necesarios. En lo que se refiere a las imágenes, "no esencial" generalmente es sinónimo de "fuera de pantalla". Si utilizaste Lighthouse y exploraste algunas oportunidades de mejora, sin dudas obtuviste cierta orientación en este ámbito en la auditoría Imágenes fuera de pantalla.

Seguramente, ya viste la carga diferida en acción alguna vez. Se parece a esto:

  • Llegas a una página. Te desplazas a medida que lees el contenido.
  • En cierto punto, te desplazas hasta una imagen de marcador de posición en la ventana de visualización.
  • De repente, la imagen de marcador de posición se reemplaza por la imagen final.
Es posible ver un ejemplo de carga diferida de imagen en este sitio web de Tutoriales en linea, que carga imágenes de marcador de posición ligeras en el tiempo de carga y las reemplaza por imágenes de carga diferida a medida que se desplazan en la ventana de visualización.
Figura 1. Un ejemplo de carga diferida de imagen en acción. Se carga una imagen de marcador de posición en la carga de la página (izquierda) y, al desplazarse a la ventana de visualización, se carga la imagen final cuando se necesita.

Si no conoces bien la carga diferida, seguramente te preguntas qué tan útil es esta técnica y cuáles son sus beneficios. ¡Continúa leyendo para descubrirlo!

Carga diferida de imágenes 1v6q2s


En teoría, los mecanismos de carga diferida de imágenes son simples, pero los detalles son algo complicados. Además, existen algunos casos de uso puntuales en los que la carga diferida aporta beneficios. Comencemos por la carga diferida de imágenes incorporadas en HTML.

Imágenes incorporadas 1j5e2n


Los candidatos más comunes para la carga diferida son las imágenes que se utilizan en los elementos <img>. Cuando se cargan de forma diferida elementos <img>, se utiliza jаvascript para comprobar si se encuentran en la ventana de visualización. Si se encuentran, sus atributos src (y a veces srcset) se rellenan con direcciones URL al contenido de imagen deseado.

Uso de Intersection Observer 3v2at


Intersection Observer es una API más fácil de usar y leer que el código basado en diversos controladores de eventos, ya que los desarrolladores solo deben registrar una instancia de Intersection Observer para vigilar los elementos en lugar de escribir el tedioso código de detección de visibilidad de elementos. Todo lo que el desarrollador debe hacer es decidir qué hacer cuando un elemento se vuelve visible. Supongamos que este es el patrón de marcado básico para los elementos <img>cargados de forma diferida:
<img class="lazy" src="placeholder-image.webp" data-src="image-to-lazy-load-1x.webp" data-srcset="image-to-lazy-load-2x.webp 2x, image-to-lazy-load-1x.webp 1x" alt="Soy una imagen!">
Debemos enfocarnos en tres partes relevantes de este marcado:

  1. El atributo class, que es con lo que seleccionaremos el elemento en jаvascript.
  2. El atributo src, que hace referencia a una imagen de marcador de posición que aparecerá cuando se cargue la página por primera vez.
  3. Los atributos data-src y data-srcset, que son atributos de marcador de posición y contienen la URL para la imagen que cargaremos cuando el elemento se encuentre en la ventana de visualización.
Ahora veamos la forma en que podemos usar Intersection Observer en jаvascript para cargar imágenes de forma diferida con este patrón de marcado:
document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.srcset = lazyImage.dataset.srcset;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });

    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // Possibly fall back to a more compatible method here
  }
});
Mas sobre Intersection Observer

Imágenes en CSS 6o4t35


Si bien las etiquetas <img> son la forma más común de usar imágenes en páginas web, también es posible invocar imágenes mediante la propiedad CSS background-image (y otras propiedades). A diferencia de los elementos <img> que se cargan independientemente de su visibilidad, el comportamiento de carga de imágenes en CSS implica más especulación. Cuando se crean los modelos de documento y objeto CSS y el árbol de representación, el navegador examina la forma en que se aplica CSS a un documento antes de solicitar recursos externos. Si el navegador determina una regla de CSS por la que un recurso externo no se aplica al documento en función de su construcción actual, el navegador no lo solicita.

Es posible usar este comportamiento especulativo para diferir la carga de imágenes en CSS mediante jаvascript para determinar si un elemento se encuentra en la ventana de visualización y, posteriormente, aplicar una clase a ese elemento con la que se invoque el estilo de una imagen de fondo. Esto hace que la imagen se descargue cuando se necesita y no en la carga inicial. Por ejemplo, veamos un elemento que contiene una gran imagen de fondo hero:
<div class="lazy-background">
  <h1>¡Aquí hay un héroe que se dirige para llamar tu atención!</h1>
  <p>¡Aquí hay una copia del héroe para convencerte de comprar algo!</p>
  <a href="/buy-a-thing">Compra una cosa!</a>
</div>
Normalmente, el elemento div.lazy-background contiene una imagen de fondo hero invocada por alguna CSS. No obstante, en este ejemplo de carga diferida, es posible aislar la propiedad background-image del elemento div.lazy-backgroundmediante una clase visible que se agrega al elemento cuando este llegue a la ventana de visualización:
.lazy-background {
  background-image: url("hero-placeholder.webp"); /* Imagen de marcador de posición */
}

.lazy-background.visible {
  background-image: url("hero.webp"); /* La imagen final */
}
Desde aquí, se utiliza jаvascript para comprobar si el elemento se encuentra en la ventana de visualización (con Intersection Observer), y se agrega la clase visible al elemento div.lazy-backgrounden ese momento, lo que carga la imagen:
document.addEventListener("DOMContentLoaded", function() {
  var lazyBackgrounds = [].slice.call(document.querySelectorAll(".lazy-background"));

  if ("IntersectionObserver" in window) {
    let lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          entry.target.classList.add("visible");
          lazyBackgroundObserver.unobserve(entry.target);
        }
      });
    });

    lazyBackgrounds.forEach(function(lazyBackground) {
      lazyBackgroundObserver.observe(lazyBackground);
    });
  }
});

Carga diferida de videos 334461


Al igual que con los elementos de imagen, también es posible cargar de forma diferida videos. Para cargar un video en circunstancias normales, se utiliza el elemento <video> (a pesar de que ha surgido un método alternativo con <img> de implementación limitada). Sin embargo, el modo en que se carga de forma diferida <video> depende de cada caso de uso. Analicemos algunas situaciones y la solución diferente que se requiere en cada una.

Para videos sin reproducción automática 5h60a


En los videos donde el inicia la reproducción (es decir, videos sin reproducción automática), especificar el atributo preload en el elemento <video> puede ser conveniente:
<video controls preload="none" poster="one-does-not-simply-placeholder.webp">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Aquí, se usa un atributo preload con el valor none para evitar que los navegadores precarguen cualquier dato de video. Para ocupar el espacio, se usa el atributo poster para otorgar un marcador de posición al elemento <video>. El motivo de esto es que los comportamientos predeterminados de carga de video pueden variar de un navegador a otro:

  • En Chrome, el valor predeterminado para preload era auto. A partir de Chrome 64, el valor predeterminado es metadata. Aun así, en la versión de Chrome para equipos de escritorio, es posible que se precargue una porción de video con el encabezado Content-Range. Firefox, Internet Explorer 11 y Edge se comportan de un modo similar.
  • Al igual que Chrome en los equipos de escritorio, las versiones de Safari 11.0 para escritorio precargan un intervalo de video. En la versión 11.2 (la versión Tech Preview actual de Safari), solo se precargan los metadatos de video. En Safari en iOS, nunca se precargan los videos.
  • Cuando se habilita el modo de ahorro de datos, el valor predeterminado de preload es none.
Como los comportamientos predeterminados de los navegadores con respecto a preload no son inamovibles, ser explícitos es probablemente la mejor jugada. En los casos donde el inicia la reproducción, el uso de preload="none" es la forma más fácil de diferir la carga de un video en todas las plataformas. El atributo preload no es la única forma de diferir la carga de contenido de video. En Reproducción rápida con carga previa de video, es posible obtener algunas ideas y conocimientos sobre el trabajo con la reproducción de video en jаvascript.

Carga diferida de bibliotecas 6n3e49


Si no te importa tanto saber cómo funciona la carga diferida en detalle y solo deseas seleccionar una biblioteca y comenzar (¡eso no tiene nada de malo!), dispones de muchas opciones para elegir. Muchas bibliotecas utilizan un patrón de marcado similar a los que se mostraron en este tutorial. Estas son algunas bibliotecas de carga diferida que puedes considerar útiles:

  • lazysizes es una biblioteca de carga diferida con todas las funciones para cargar de forma diferida imágenes e iframes. Utiliza un patrón bastante similar a los ejemplos de código mostrados aquí, ya que se enlaza automáticamente a una clase lazyload en los elementos <img> y requiere especificar URL de imagen en los atributos data-src y/o data-srcset, cuyo contenido se intercambia por los atributos src y/o srcset, respectivamente. Utiliza Intersection Observer (donde se puede aplicar polyfill) y se puede ampliar con diversos complementos para tareas como la carga diferida de videos.
  • lozad.js es una opción súper ligera que solo utiliza Intersection Observer. Por esto, es altamente eficaz, pero requiere polyfill para poder utilizarla en navegadores anteriores.
  • blazy es otra opción similar que se factura como un cargador diferido ligero (su tamaño es 1.4 KB). Al igual que con los tamaños diferidos, no requiere utilidades de terceros para la carga y funciona con IE7+. Lamentablemente, no utiliza Intersection Observer.
  • yall.js es una biblioteca de mi autoría que utiliza IntersectionObserver y se revierte a los controladores de eventos. Es compatible con IE11 y los principales navegadores.
  • Si buscas una biblioteca de carga diferida específica para React, puedes considerar el uso de react-lazyload. Si bien no utiliza Intersection Observer, sí proporciona un método conocido de carga diferida de imágenes para los s habituados a desarrollar aplicaciones con React.
Cada una de estas bibliotecas de carga diferida está bien documentada y con ejemplos, con muchos patrones de marcado para diversos esfuerzos de carga diferida. Si no eres de realizar cambios, toma una biblioteca y comienza. Requiere el mínimo esfuerzo.
Compartir

Mi nombre es Alexander fundador y CEO, y me gusta llamarme un Geek. Amo la informática, tecnología y todo lo que está relacionado con ella. Inicié este sitio con la intención de compartir conocimientos como cursos en línea, tutoriales y videotutoriales. Estoy muy entusiasmado con la información que he descubierto y compartido hasta el momento. La verdad es que lo he hecho con el mayor de los gustos. Así es, soy un Geek con una visión para compartir conocimiento. Leer mas... 2c611u