Fecha de publicación: 16 de agosto de 2019; última actualización: 2 de julio de 2026
Al igual que con los elementos de imagen, también puedes cargar videos de forma diferida. Los videos suelen cargarse con el elemento <video>, aunque, en el caso de los videos alojados en otros servicios, como YouTube, pueden usar <iframe>s (en ese caso, consulta el artículo sobre carga diferida de iframes).
La forma de cargar <video> de forma diferida depende del caso de uso, ya que existen varias soluciones diferentes.
Cómo usar el atributo loading
Los navegadores comenzaron a admitir el atributo loading en los elementos multimedia (<video> y <audio>). Cuando se admite, esto significa que tanto el contenido multimedia como cualquier imagen de póster se cargan de forma diferida automáticamente con solo agregar el atributo loading="lazy":
<video controls loading="lazy" 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>
El uso de loading="lazy" evitará que se cargue la imagen poster hasta que esté en la ventana gráfica o cerca de ella, y, luego, usará el atributo preload para decidir qué parte de video cargar. Esto también significa que los videos autoplay no se reproducirán automáticamente hasta que estén dentro o cerca de la ventana gráfica. El atributo loading="lazy" funciona con los atributos poster, preload y autoplay, y no reemplaza la necesidad de usarlos.
Los navegadores que no admiten el atributo loading en los elementos multimedia ignorarán este atributo, lo que provocará que la imagen poster se cargue de inmediato y que el video se cargue según el atributo preload, que veremos a continuación.
Usa el atributo preload para realizar la carga diferida de videos que no se reproducen automáticamente
Por lo general, evitar la reproducción automática de videos es una práctica recomendada, ya que deja el control en manos del usuario. En estos casos, especificar el atributo preload en el elemento <video> es la mejor manera de evitar cargar todo el video hasta que sea necesario:
<video controls loading="lazy" 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 carguen previamente cualquier dato de video, incluso cuando se encuentra en el viewport. El atributo poster le da al elemento <video> un marcador de posición que ocupará el espacio mientras se carga el video.
En la mayoría de los navegadores, preload se establece de forma predeterminada en metadata y se precarga una parte del video con el encabezado Content-Range. Esto puede generar que se descarguen más datos de los deseados, ya que los navegadores no pueden saber en qué bytes se almacenan los metadatos, y es posible que no se almacenen al principio del archivo. Por lo tanto, la mejor manera de evitar que se cargue el video es usar preload="none".
Esto se puede mejorar aún más para precargar los metadatos cuando el usuario coloca el cursor sobre el video con un atributo onmouseenter (o con el controlador de eventos mouseenter equivalente):
<video controls
loading="lazy"
preload="none"
poster="one-does-not-simply-placeholder.jpg"
onmouseenter="event.target.setAttribute('preload','metadata')">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Esto no solo reduce la demora cuando el usuario reproduce el video, sino que también muestra su duración en cuanto lo hace.
Los videos pueden cumplir con los requisitos para ser candidatos a LCP. Una imagen poster se cargará más rápido que el video, por lo que, cuando sea candidata para el LCP, debes usar una imagen de póster, pero también precargarla con un valor de atributo fetchpriority de "high", ya que en el momento de escribir este artículo, no puedes especificar el atributo fetchpriority para los atributos de póster:
<link rel="preload" href="one-does-not-simply-placeholder.jpg" as="image" fetchpriority="high">
<video controls preload="none"
poster="one-does-not-simply-placeholder.jpg"
onmouseenter="event.target.setAttribute('preload','metadata')">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Los videos que son elementos de LCP no deben usar loading="lazy", de la misma manera que no debes cargar de forma diferida los videos de imágenes de LCP .
Para videos que actúan como reemplazo de un GIF animado
Los videos de reproducción automática se suelen usar para animaciones rápidas de estilo GIF. Si bien los GIFs animados se usan mucho, son inferiores a sus equivalentes en video en varios aspectos, en particular en el tamaño del archivo. Los GIFs animados pueden ocupar varios megabytes de datos. Los videos con una calidad visual similar suelen ser mucho más pequeños.
Usar el elemento <video> como reemplazo de un GIF animado no es tan sencillo como usar el elemento <img>. Los GIFs animados tienen tres características:
- Se reproducen automáticamente cuando se cargan.
- Se repiten de forma continua (aunque no siempre es así).
- No tienen una pista de audio.
Para lograr esto con el elemento <video>, el código se verá 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>
El atributo loading="lazy" evita que se cargue el video hasta que esté cerca del viewport. Los atributos autoplay, muted y loop son explicativos. playsinline es necesario para que se reproduzca automáticamente en iOS.
Ahora tienes un reemplazo de video por GIF que funciona en todas las plataformas. Pero, ¿cómo se realiza la carga diferida?
En el caso de los navegadores que admiten esta opción, loading="lazy" es la más sencilla:
<video loading="lazy" 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>
Para admitir la carga diferida de videos en otros navegadores, debes usar JavaScript y modificar el lenguaje de marcado de tu <video> según corresponda:
<video class="lazy" preload="none" controls muted loop playsinline width="610" height="254" poster="one-does-not-simply.jpg">
<source src="one-does-not-simply.webm" type="video/webm">
<source src="one-does-not-simply.mp4" type="video/mp4">
</video>
Verás que se quitó autoplay y se agregaron los atributos class="lazy", preload="none" y poster, que te permiten especificar un marcador de posición para ocupar el espacio del elemento <video> hasta que se cargue el video de forma diferida. Luego, usamos un Intersection Observer de JavaScript para volver a habilitar la reproducción automática:
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) {
video.target.removeAttribute('preload');
video.target.removeAttribute('controls');
video.target.autoplay = true;
video.target.classList.remove("lazy");
lazyVideoObserver.unobserve(video.target);
}
});
});
lazyVideos.forEach(function(lazyVideo) {
lazyVideoObserver.observe(lazyVideo);
});
}
});
Con este método, el video no se reproduce automáticamente de forma predeterminada, sino solo cuando el observador de intersección detecta que el video ingresa al viewport. Además, el atributo controls controla los casos en los que falla JavaScript. En conjunto, esto significa que tienes una solución de video que emula el comportamiento de los GIFs animados, pero no genera el mismo uso intensivo de datos que los GIFs animados, y puedes cargar ese contenido de forma diferida.
Bibliotecas de carga diferida
Las siguientes bibliotecas pueden ayudarte a cargar videos de forma diferida:
- vanilla-lazyload y lozad.js son opciones muy ligeras que solo usan Intersection Observer. Por lo tanto, tienen un alto rendimiento, pero deberán rellenarse antes de que puedas usarlos en navegadores más antiguos.
- Si necesitas una biblioteca de carga diferida específica para React, puedes considerar react-lazyload. Si bien no usa Intersection Observer, sí proporciona un método conocido de carga diferida de imágenes para quienes están acostumbrados a desarrollar aplicaciones con React.
Cada una de estas bibliotecas de carga diferida está bien documentada y cuenta con muchos patrones de marcado para tus diversos proyectos de carga diferida.
A medida que el atributo loading para <video> esté disponible en más navegadores, esperamos que las soluciones de JavaScript (incluidas las bibliotecas) se usen menos en favor de las soluciones integradas, excepto para quienes deseen tener más control del que permiten.