Carga diferida de imágenes y elementos de <iframe>

Las imágenes y los elementos <iframe> suelen consumir más ancho de banda que otros tipos de recursos. En el caso de los elementos <iframe>, una buena cantidad de tiempo adicional de procesamiento puede implicar la carga y la renderización de las páginas dentro de ellos.

En el caso de las imágenes de carga diferida, aplazar la carga de las imágenes que están fuera del viewport inicial puede ser útil para reducir la contención del ancho de banda para recursos más críticos dentro del viewport inicial. Esto puede mejorar el Largest Contentful Paint (LCP) de una página en algunos casos en los que las conexiones de red son deficientes, y ese ancho de banda reasignado puede ayudar a los candidatos de LCP a cargarse y pintar más rápido.

En lo que respecta a los elementos <iframe>, se puede mejorar la Interacción a la siguiente pintura (INP) de una página durante el inicio mediante la carga diferida. Esto se debe a que un <iframe> es un documento HTML completamente independiente con sus propios subrecursos. Si bien los elementos <iframe> se pueden ejecutar en un proceso separado, no es raro que compartan un proceso con otros subprocesos, lo que puede crear condiciones en las que las páginas son menos responsivas a las entradas del usuario.

Por lo tanto, aplazar la carga de imágenes fuera de pantalla y elementos <iframe> es una técnica que vale la pena seguir y requiere un esfuerzo bastante bajo para obtener un retorno razonablemente bueno en términos de rendimiento. En este módulo, se explica cómo realizar la carga diferida de estos dos tipos de elementos para obtener una experiencia del usuario más rápida y mejor durante el período crítico de inicio de la página.

Imágenes de carga diferida con el atributo loading

Se puede agregar el atributo loading a los elementos <img> para indicarles a los navegadores cómo deben cargarse:

  • "eager" informa al navegador que la imagen se debe cargar de inmediato, incluso si está fuera del viewport inicial. Este también es el valor predeterminado del atributo loading.
  • "lazy" aplaza la carga de una imagen hasta que se encuentre dentro de una distancia establecida del viewport visible. Esta distancia varía según el navegador, pero a menudo se configura para que sea lo suficientemente grande como para que la imagen se cargue cuando el usuario se desplace hacia ella.

También vale la pena tener en cuenta que, si usas el elemento <picture>, el atributo loading debe aplicarse de todos modos al elemento <img> secundario, no al elemento <picture> en sí. Esto se debe a que el elemento <picture> es un contenedor que contiene elementos <source> adicionales que apuntan a diferentes opciones de imagen, y el candidato que elige el navegador se aplica directamente al elemento <img> secundario.

No cargues de forma diferida las imágenes que se encuentran en el viewport inicial

Solo debes agregar el atributo loading="lazy" a los elementos <img> que se encuentren fuera del viewport inicial. Sin embargo, puede ser complejo conocer la posición precisa de un elemento relativa dentro del viewport antes de que se renderice la página. Se deben tener en cuenta los diferentes tamaños de viewport, las relaciones de aspecto y los dispositivos.

Por ejemplo, un viewport de computadora de escritorio puede ser bastante diferente de uno de un teléfono celular, ya que renderiza más espacio vertical, que puede incluir imágenes en el viewport inicial que no aparecerían en el viewport inicial de un dispositivo físicamente más pequeño. Las tablets que se usan en orientación vertical también muestran una cantidad considerable de espacio vertical, quizás incluso más que algunos dispositivos de escritorio.

Sin embargo, hay algunos casos en los que es bastante claro que debes evitar aplicar loading="lazy". Por ejemplo, definitivamente debes omitir el atributo loading="lazy" de los elementos <img> en casos de imágenes hero o en otros casos de uso de imágenes en los que es probable que los elementos <img> aparezcan en la parte superior de la página o cerca de la parte superior del diseño en cualquier dispositivo. Esto es aún más importante para las imágenes que probablemente sean candidatas a LCP.

Las imágenes de carga diferida deben esperar a que el navegador termine el diseño para saber si la posición final de la imagen se encuentra dentro del viewport. Esto significa que si un elemento <img> en el viewport visible tiene un atributo loading="lazy", solo se solicita después de que se descarga, analiza y aplica todo el CSS a la página, a diferencia de lo que se recupera en cuanto el escáner de precarga lo descubre en el lenguaje de marcado sin procesar.

Dado que el atributo loading del elemento <img> es compatible con todos los navegadores principales, no es necesario usar JavaScript para cargar imágenes de forma diferida, ya que agregar JavaScript adicional a una página para proporcionar las capacidades que el navegador ya proporciona afecta otros aspectos del rendimiento de la página, como INP.

Demostración de carga diferida de imágenes

Carga diferida de elementos <iframe>

La carga diferida de los elementos <iframe> hasta que sean visibles en el viewport puede ahorrar datos significativos y mejorar la carga de los recursos críticos necesarios para que se cargue la página de nivel superior. Además, como los elementos <iframe> son básicamente documentos HTML completos cargados en un documento de nivel superior, pueden incluir una cantidad significativa de subrecursos, en particular JavaScript, lo que puede afectar considerablemente el INP de una página si las tareas dentro de esos marcos requieren un tiempo de procesamiento significativo.

Las incorporaciones de terceros son un caso de uso común para los elementos <iframe>. Por ejemplo, los reproductores de video incorporados o las publicaciones en redes sociales suelen usar elementos <iframe> y, a menudo, requieren una cantidad significativa de subrecursos, lo que también puede generar una contención de ancho de banda para los recursos de la página de nivel superior. Por ejemplo, la carga diferida de la incorporación de un video de YouTube permite ahorrar más de 500 KiB durante la carga inicial de la página, mientras que la carga diferida del complemento del botón "Me gusta" de Facebook ahorra más de 200 KiB, la mayoría de los cuales es JavaScript.

De cualquier manera, siempre que tengas un elemento <iframe> en la mitad inferior de la página en una página, considera la carga diferida en caso de que no sea fundamental hacerlo por adelantado, ya que esto puede mejorar significativamente la experiencia del usuario.

El atributo loading para los elementos <iframe>

El atributo loading en los elementos <iframe> también es compatible con todos los navegadores principales. Los valores del atributo loading y sus comportamientos son los mismos que con los elementos <img> que usan el atributo loading:

  • "eager" es el valor predeterminado. Informa al navegador que debe cargar inmediatamente el código HTML del elemento <iframe> y sus subrecursos.
  • "lazy" aplaza la carga del HTML del elemento <iframe> y sus subrecursos hasta que se encuentra dentro de una distancia predefinida del viewport.

Demostración de carga diferida de iframes

Fachadas

En lugar de cargar una incorporación de inmediato mientras se carga la página, puedes cargarla a pedido en respuesta a la interacción del usuario. Para ello, se muestra una imagen o algún otro elemento HTML adecuado hasta que el usuario interactúe con ella. Una vez que el usuario interactúe con el elemento, puedes reemplazarlo por la incorporación de terceros. Esta técnica se conoce como fachada.

Un caso de uso común para las fachadas son las incorporaciones de video de servicios de terceros, en las que la incorporación puede implicar la carga de muchos subrecursos adicionales y potencialmente costosos, como JavaScript, además del contenido del video. En ese caso (a menos que haya una necesidad legítima de que un video se reproduzca automáticamente), las incorporaciones de video requieren que el usuario interactúe con ellas antes de reproducir el video haciendo clic en el botón de reproducción.

Esta es una excelente oportunidad para mostrar una imagen estática que es visualmente similar a la incorporación de video y ahorrar una gran cantidad de ancho de banda en el proceso. Una vez que el usuario hace clic en la imagen, se reemplaza por la incorporación real de <iframe>, que activa el HTML del elemento <iframe> de terceros y sus subrecursos para comenzar a descargarse.

Además de mejorar la carga inicial de la página, otra ventaja clave es que, si el usuario nunca reproduce el video, los recursos necesarios para publicarlo nunca se descargan. Este es un buen patrón, ya que garantiza que el usuario solo descargue lo que realmente desea, sin hacer suposiciones potencialmente erróneas sobre sus necesidades.

Los widgets de chat son otro excelente caso de uso de la técnica de fachada. La mayoría de los widgets de chat descargan cantidades significativas de JavaScript, lo que puede afectar de forma negativa la carga de la página y la capacidad de respuesta a las entradas del usuario. Al igual que cuando se carga algo por adelantado, el costo se genera al momento de la carga, pero en el caso de un widget de chat, no todos los usuarios nunca pretenden interactuar con él.

Por otro lado, si hay una fachada, es posible reemplazar el botón de terceros "Iniciar chat" por uno falso. Una vez que el usuario interactúa de manera significativa con él (por ejemplo, mantiene el puntero sobre él durante un período razonable o hace un clic), el widget de chat real y funcional se coloca en su lugar cuando el usuario lo necesita.

Si bien es posible crear tus propias fachadas, hay opciones de código abierto disponibles para terceros más populares, como lite-youtube-embed para videos de YouTube, lite-vimeo-embed para videos de Vimeo y React Live Chat Loader para widgets de chat.

Bibliotecas de carga diferida de JavaScript

Si necesitas cargar de forma diferida elementos <video>, imágenes poster de elementos <video>, imágenes cargadas por la propiedad background-image de CSS o algún otro elemento no compatible, puedes hacerlo con una solución de carga diferida basada en JavaScript, como lazysizes o yall.js, ya que la carga diferida de estos tipos de recursos no es una función a nivel del navegador.

En particular, los elementos <video> que se reproducen automáticamente y se repiten indefinidamente sin una pista de audio son una alternativa mucho más eficiente que usar GIF animados, que suelen ser varias veces más grandes que un recurso de video de calidad visual equivalente. Aun así, estos videos pueden ser significativos en términos de ancho de banda, por lo que cargarlos de forma diferida es una optimización adicional que puede ser muy útil para reducir el ancho de banda desperdiciado.

La mayoría de estas bibliotecas funcionan con la API de Intersection Observer (y, además, la API de Mutation Observer si el HTML de una página cambia después de la carga inicial) para reconocer cuando un elemento ingresa en el viewport del usuario. Si la imagen es visible (o se acerca al viewport), la biblioteca JavaScript reemplaza el atributo no estándar (a menudo data-src o un atributo similar) por el atributo correcto, como src.

Supongamos que tienes un video que reemplaza un GIF animado, pero quieres cargarlo de forma diferida con una solución de JavaScript. Esto es posible con yall.js con el siguiente patrón de lenguaje de marcado:

<!-- The autoplay, loop, muted, and playsinline attributes are to
     ensure the video can autoplay without user intervention. -->
<video class="lazy" autoplay loop muted playsinline width="320" height="480">
  <source data-src="video.webm" type="video/webm">
  <source data-src="video.mp4" type="video/mp4">
</video>

De forma predeterminada, yall.js observa todos los elementos HTML que califican con una clase "lazy". Una vez que yall.js se cargue y se ejecute en la página, el video no se cargará hasta que el usuario lo desplace al viewport. En ese momento, los atributos data-src de los elementos secundarios <source> del elemento <video> se intercambian con los atributos src, lo que envía una solicitud para descargar el video y comienza a reproducirlo automáticamente.

Pon a prueba tus conocimientos

¿Cuál es el valor predeterminado del atributo loading para los elementos <img> y <iframe>?

"eager"
Correcto.
"lazy"
Vuelve a intentarlo.

¿Cuándo es razonable usar las soluciones de carga diferida basadas en JavaScript?

Para cualquier recurso que pueda ser de carga diferida.
Vuelve a intentarlo.
Para recursos en los que no se admite el atributo loading, como en el caso de los videos de reproducción automática diseñados para reemplazar imágenes animadas o para cargar de forma diferida la imagen de póster de un elemento <video>
Correcto.

¿Cuándo es una técnica útil la fachada?

Para cualquier incorporación de terceros que consuma datos significativos, sin importar las necesidades del usuario
Vuelve a intentarlo.
Para cualquier incorporación de terceros en la que los recursos necesarios para cargar no solo sean sustanciales, sino que hay una buena probabilidad de que no todos los usuarios interactúen con ellos.
Correcto.

A continuación: Carga previa y renderización previa

Ahora que tienes un control sobre la carga diferida de imágenes y elementos <iframe>, estás en una buena posición para garantizar que las páginas se carguen más rápido y, a su vez, se respeten las necesidades de los usuarios. Sin embargo, hay casos en los que se recomienda realizar una carga especulativa de recursos. En el siguiente módulo, obtén información sobre la carga previa y la renderización previa, y sobre cómo estas técnicas, cuando se usan con cuidado, pueden acelerar considerablemente la navegación a páginas posteriores cargándolas con anticipación.