Carga diferida de videos

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

Para videos que no se reproducen automáticamente

En el caso de los videos en los que el usuario inicia la reproducción (es decir, videos que no se reproducen automáticamente), puede ser 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 el valor 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, el valor predeterminado de preload solía ser auto, pero a partir de Chrome 64, el valor predeterminado ahora es metadata. Sin embargo, en la versión de Chrome para computadoras de escritorio, es posible que se precarga una parte del video con el encabezado Content-Range. Otros navegadores basados en Chromium y Firefox se comportan de manera similar.
  • Al igual que con Chrome en computadoras de escritorio, la versión 11.0 de Safari precargará un rango del 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 se habilita el modo de Ahorro de datos, preload se establece de forma predeterminada en none.

Como los comportamientos predeterminados de los navegadores con respecto a preload no son inamovibles, ser explícitos es probablemente la mejor opción. En estos casos, cuando el usuario inicia la reproducción, usar preload="none" es la forma más fácil de diferir la carga del video en todas las plataformas. El atributo preload no es la única forma de diferir la carga del contenido de video. La sección Reproducción rápida con precarga de video puede brindarte algunas ideas y estadísticas para trabajar con la reproducción de videos en JavaScript.

Lamentablemente, no es útil para usar videos en lugar de GIF animados, que analizaremos a continuación.

Para videos que funcionan como reemplazo de GIF animados

Si bien los GIF animados se usan ampliamente, son diferentes a los equivalentes de los videos en algunos aspectos, sobre todo en tamaño de archivo. Los GIF animados pueden alcanzar al rango de varios megabytes de datos. Los videos con una calidad visual similar tienden a ser mucho más pequeños.

Usar el elemento <video> como reemplazo de un 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 no requieren explicación. playsinline es necesario para que la reproducción automática ocurra en iOS. Ahora tienes un reemplazo de video como GIF que se puede usar en todas las plataformas. ¿Pero cómo abordar 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 realice la carga diferida del 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>. Luego, usa un código JavaScript similar al de los ejemplos de carga diferida de imágenes basados 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 girar sus atributos data-src a los atributos src. Una vez que lo hagas, deberás activar la carga del video llamando al método load del elemento. Luego, 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 que no genera el mismo uso intensivo de datos que los GIF animados, y puedes realizar una carga diferida de ese contenido.

Carga diferida de bibliotecas

Las siguientes bibliotecas pueden ayudarte a realizar una carga diferida de videos:

  • vanilla-lazyload y lozad.js son opciones muy ligeras que solo usan Intersection Observer. Por lo tanto, tienen un alto rendimiento, pero se necesitarán polyfills 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, te recomendamos usar react-lazyload. Si bien no utiliza Intersection Observer, proporciona un método conocido de carga diferida de imágenes para los usuarios acostumbrados a desarrollar aplicaciones con React.

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