Carga diferida de videos

Al igual que con los elementos de imagen, también puedes subir videos de carga diferida. Por lo general, los videos se cargan con el elemento <video> (aunque surgió un método alternativo con <img> con implementación limitada). Sin embargo, cómo realizar una carga diferida de <video> depende del caso de uso. Analicemos un par de situaciones que requieren una solución diferente.

Para videos sin reproducción automática

En el caso de los videos en los que el usuario inicia la reproducción (es decir, videos que no se reproducen automáticamente), es conveniente especificar el atributo preload en el elemento <video>:

<video controls preload="none" poster="one-does-not-simply-placeholder.jpg">
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

En el ejemplo anterior, se usa un atributo preload con un valor de none para evitar que los navegadores precarguen cualquier dato de video. El atributo poster le da al elemento <video> un marcador de posición que ocupará el espacio mientras se carga el video. Esto se debe a que los comportamientos predeterminados de carga de videos pueden variar de un navegador a otro:

  • En Chrome, la configuración predeterminada para preload era auto. Sin embargo, a partir de Chrome 64, el valor predeterminado es metadata. Aun así, en la versión para computadoras de Chrome, es posible que una parte del video se precargue con el encabezado Content-Range. Otros navegadores basados en Chromium y Firefox se comportan de manera similar.
  • Al igual que con Chrome para computadoras de escritorio, las versiones de Safari 11.0 para computadoras de escritorio precargan un rango de video. A partir de la versión 11.2, solo se precargan los metadatos del video. En Safari para iOS, los videos nunca se precargan.
  • Cuando el modo de Ahorro de datos está habilitado, 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 la mejor jugada. En los casos en los que el usuario inicia la reproducción, usar 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 que obtengas algunas ideas y estadísticas para trabajar con la reproducción de video en JavaScript.

Lamentablemente, esto no resulta útil si quieres usar videos en lugar de GIF animados, como se explica a continuación.

Para videos que sirvan como reemplazo de GIF animado

Si bien los GIF animados se utilizan ampliamente, son inferiores a los equivalentes de video en varios aspectos, especialmente en cuanto al tamaño de archivo. Los GIF animados pueden alcanzar el rango de varios megabytes de datos. Los videos con una calidad visual similar tienden a ser mucho más pequeños.

El uso del elemento <video> como reemplazo de GIF animado no es tan sencillo como el elemento <img>. Los GIF animados tienen tres características:

  1. Se reproducen automáticamente cuando se cargan.
  2. Se repiten de forma continua (aunque no siempre es así).
  3. No tienen una pista de audio.

Lograr esto con el elemento <video> se ve de la siguiente manera:

<video autoplay muted loop playsinline>
  <source src="one-does-not-simply.webm" type="video/webm">
  <source src="one-does-not-simply.mp4" type="video/mp4">
</video>

Los atributos autoplay, muted y loop se explican a sí mismos. playsinline es necesario para que la reproducción automática tenga lugar en iOS. Ahora tienes un reemplazo de video como GIF que se puede usar en todas las plataformas. Pero ¿cómo hacer la carga diferida? Para comenzar, modifica el lenguaje de marcado de <video> según corresponda:

<video class="lazy" autoplay muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
  <source data-src="one-does-not-simply.webm" type="video/webm">
  <source data-src="one-does-not-simply.mp4" type="video/mp4">
</video>

Notarás que se agregó el atributo poster, que te permite especificar un marcador de posición para que ocupe el espacio del elemento <video> hasta que se cargue de forma diferida el video. Al igual que con los ejemplos de carga diferida de <img>, almacena la URL del video en el atributo data-src de cada elemento <source>. Desde allí, usa código JavaScript similar a los ejemplos de carga diferida de imágenes basadas en Intersection Observer:

document.addEventListener("DOMContentLoaded", function() {
  var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));

  if ("IntersectionObserver" in window) {
    var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(video) {
        if (video.isIntersecting) {
          for (var source in video.target.children) {
            var videoSource = video.target.children[source];
            if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
              videoSource.src = videoSource.dataset.src;
            }
          }

          video.target.load();
          video.target.classList.remove("lazy");
          lazyVideoObserver.unobserve(video.target);
        }
      });
    });

    lazyVideos.forEach(function(lazyVideo) {
      lazyVideoObserver.observe(lazyVideo);
    });
  }
});

Cuando realizas una carga diferida de un elemento <video>, debes iterar a través de todos los elementos <source> secundarios y cambiar sus atributos data-src por los atributos src. Una vez que lo hayas hecho, deberás activar la carga del video llamando al método load del elemento, después de lo cual el contenido multimedia comenzará a reproducirse automáticamente según el atributo autoplay.

Con este método, tienes una solución de video que emula el comportamiento de los GIF animados, pero no genera el mismo uso de datos intensivo que los GIF animados, y puedes realizar una carga diferida de ese contenido.

Carga diferida de bibliotecas

Las siguientes bibliotecas pueden ayudarte a realizar cargas diferidas de video:

  • vanilla-lazyload y lozad.js son opciones muy ligeras que solo usan Intersection Observer. Por lo tanto, tienen un alto rendimiento, pero deberán incluir polyfill para poder usarlas en navegadores más antiguos.
  • yall.js es una biblioteca que usa Intersection Observer y recurre a los controladores de eventos. También puede cargar de forma diferida imágenes poster de video mediante un atributo data-poster.
  • Si necesitas una biblioteca de carga diferida específica para React, puedes considerar usar react-lazyload. Si bien no usa Intersection Observer, proporciona un método conocido de imágenes de carga diferida para aquellos acostumbrados a desarrollar aplicaciones con React.

Cada una de estas bibliotecas de carga diferida está bien documentada, con muchos patrones de marcado para tus diversos esfuerzos de carga diferida.