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>, la carga y la renderización de las páginas que contienen pueden implicar una cantidad considerable de tiempo de procesamiento adicional.

En el caso de las imágenes con carga diferida, aplazar la carga de las imágenes que se encuentran fuera del viewport inicial puede ser útil para reducir la contención del ancho de banda de los recursos más críticos dentro del viewport inicial. En algunos casos en los que las conexiones de red son deficientes, esto puede mejorar el Procesamiento de imagen con contenido más grande (LCP) de una página, y ese ancho de banda reasignado puede ayudar a que los candidatos a LCP se carguen y rendericen más rápido.

En el caso de los elementos <iframe>, se puede mejorar la Interaction to Next Paint (INP) de una página durante el inicio cargándolos de forma diferida. Esto se debe a que un <iframe> es un documento HTML completamente independiente con sus propios recursos secundarios. 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 se vuelven menos responsivas a la entrada del usuario.

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

Carga diferida de imágenes con el atributo loading

El atributo loading se puede agregar 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" difiere la carga de una imagen hasta que se encuentra a una distancia establecida del viewport visible. Esta distancia varía según el navegador, pero suele establecerse de forma que la imagen se cargue cuando el usuario se desplace hasta ella.

También vale la pena destacar que, si usas el elemento <picture>, el atributo loading se debe aplicar a su elemento secundario <img>, no al elemento <picture> en sí. Esto se debe a que el elemento <picture> es un contenedor que incluye elementos <source> adicionales que apuntan a diferentes candidatos de imágenes, y el candidato que elige el navegador se aplica directamente a su elemento secundario <img>.

No uses la carga diferida para las imágenes que se encuentran en el viewport inicial

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

Por ejemplo, un viewport de escritorio puede ser muy diferente de un viewport en un teléfono celular, ya que renderiza más espacio vertical, lo que puede permitir que se ajusten 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, tal vez incluso más que algunos dispositivos de escritorio.

Sin embargo, en algunos casos, es bastante claro que debes evitar aplicar loading="lazy". Por ejemplo, definitivamente debes omitir el atributo loading="lazy" de los elementos <img> en los casos de imágenes de héroe o en otros casos de uso de imágenes en los que es probable que los elementos <img> aparezcan en la mitad 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 al LCP.

Las imágenes que se cargan de forma diferida deben esperar a que el navegador finalice el diseño para saber si la posición final de la imagen está dentro de la ventana gráfica. Esto significa que, si un elemento <img> en el viewport visible tiene un atributo loading="lazy", solo se solicita después de que se descargue, analice y aplique todo el CSS a la página, en lugar de recuperarse tan pronto como el escáner de carga previa 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 capacidades que el navegador ya ofrece afecta otros aspectos del rendimiento de la página, como el INP.

Demostración de carga diferida de imágenes

Carga diferida de elementos <iframe>

La carga diferida de elementos <iframe> hasta que se ven en la ventana gráfica puede ahorrar una cantidad significativa de datos y mejorar la carga de los recursos críticos que se requieren para que se cargue la página de nivel superior. Además, dado que los elementos <iframe> son, básicamente, documentos HTML completos cargados dentro de un documento de nivel superior, pueden incluir una cantidad significativa de recursos secundarios, en particular JavaScript, lo que puede afectar el INP de una página de manera considerable 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 que también pueden generar contención de ancho de banda para los recursos de la página de nivel superior. Por ejemplo, la carga diferida de un video integrado de YouTube ahorra 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 son de JavaScript.

De cualquier manera, siempre que tengas un <iframe> por debajo del pliegue en una página, deberías considerar seriamente la carga diferida si no es fundamental cargarlo de inmediato, ya que hacerlo puede mejorar significativamente la experiencia del usuario.

El atributo loading para los elementos <iframe>

El atributo loading en los elementos <iframe> también se admite en 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 cargue de inmediato el HTML del elemento <iframe> y sus subrecursos.
  • "lazy" aplaza la carga del código HTML del elemento <iframe> y sus recursos secundarios hasta que se encuentre a una distancia predefinida del viewport.

Demostración de carga diferida de iframes

Fachadas

En lugar de cargar una incorporación de inmediato durante la carga de la página, puedes cargarla a pedido en respuesta a una interacción del usuario. Para ello, se puede mostrar una imagen o algún otro elemento HTML adecuado hasta que el usuario interactúe con él. Una vez que el usuario interactúa con el elemento, puedes reemplazarlo por la integració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 recursos secundarios adicionales y potencialmente costosos, como JavaScript, además del contenido de video en sí. En ese caso, a menos que haya una necesidad legítima de que un video se reproduzca automáticamente, los videos incorporados requieren que el usuario interactúe con ellos antes de la reproducción haciendo clic en el botón de reproducción.

Esta es una excelente oportunidad para mostrar una imagen estática que sea visualmente similar a la incorporación del video y ahorrar una cantidad significativa de ancho de banda en el proceso. Una vez que el usuario hace clic en la imagen, esta se reemplaza por la incorporación real de <iframe>, lo que activa el HTML del elemento <iframe> de terceros y sus recursos secundarios para que comiencen 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, no se descargan los recursos necesarios para mostrarlo. Este es un buen patrón, ya que garantiza que el usuario solo descargue lo que realmente quiere, sin hacer suposiciones posiblemente erróneas sobre las necesidades del usuario.

Los widgets de chat son otro excelente caso de uso para la técnica de fachada. La mayoría de los widgets de chat descargan cantidades significativas de JavaScript que pueden afectar de forma negativa la carga de la página y la capacidad de respuesta a las entradas del usuario. Al igual que con la carga anticipada de cualquier elemento, el costo se genera en el momento de la carga, pero, en el caso de un widget de chat, no todos los usuarios tienen la intención de interactuar con él.

Por otro lado, con una fachada, es posible reemplazar el botón externo "Iniciar chat" por un botón 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 clic en él), el widget de chat funcional real 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 de elementos poster, imágenes cargadas por la propiedad background-image de CSS o cualquier 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.<video>

En particular, los elementos <video> de reproducción automática y en bucle sin pista de audio son una alternativa mucho más eficiente que el uso de GIFs animados, que a menudo pueden ser varias veces más grandes que un recurso de video con una 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, con la API de Mutation Observer si el código HTML de una página cambia después de la carga inicial, para reconocer cuándo un elemento ingresa en la ventana gráfica del usuario. Si la imagen está visible o se acerca al viewport, la biblioteca de 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 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 aptos con una clase de "lazy". Una vez que se carga y ejecuta yall.js en la página, el video no se carga hasta que el usuario lo desplaza al viewport. En ese momento, los atributos data-src de los elementos <source> secundarios del elemento <video> se reemplazan por atributos src, lo que envía una solicitud para descargar el video y comenzar a reproducirlo automáticamente.

Ponga a prueba sus conocimientos

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

"lazy"
"eager"

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

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

¿Cuándo es útil una fachada?

Para cualquier incorporación de terceros en la que los recursos necesarios para cargar no solo sean importantes, sino que también haya una probabilidad decente de que no todos los usuarios interactúen con ellos.
Para cualquier incorporación de terceros que consuma una cantidad significativa de datos, independientemente de las necesidades del usuario.

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

Ahora que sabes cómo controlar 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, al mismo tiempo, satisfacer las necesidades de tus usuarios. Sin embargo, hay casos en los que la carga especulativa de recursos puede ser deseable. En el siguiente módulo, aprenderás sobre la recuperación previa y la renderización previa, y 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.