El arte de diferir imágenes

Cómo equilibrar técnicas de carga demorada de imágenes en Angular para lograr una experiencia de usuario fluida

Basado en el título de este artículo, comencemos con una pregunta: ¿Por qué podría considerarse el diferimiento de la carga de imágenes en un navegador web como un arte en lugar de una simple práctica de programación?

Optimizar el rendimiento web mediante el examen cuidadoso del contenido de imagen que se cargará requiere un equilibrio bien ajustado entre las limitaciones técnicas y la experiencia del usuario. Las decisiones sobre carga diferida generalmente van más allá de la implementación directa de HTML, CSS y JavaScript. Requiere juicios basados en la comprensión de la relevancia del contenido, la ubicación en el área de visualización y la interacción esperada del usuario, entre otros posibles factores.

Retrasar las imágenes no se trata solo de acelerar los tiempos de carga, sino de optimizar cómo los usuarios perciben esa mejoría. Las decisiones sobre cuándo reemplazar, por ejemplo, imágenes de alta resolución con marcadores de posición o versiones en miniatura, necesitan estar validadas por algo más que habilidades de programación. Requieren combinar conocimientos técnicos con sensibilidades de diseño visual y comprensión de las expectativas del usuario.

Carga diferida de imágenes

Antes de que el atributo HTML loading se estandarizara y adoptara en 2019 por los principales navegadores, los desarrolladores front-end tenían que depender de JavaScript para diferir la carga de imágenes que no eran críticas para mostrar desde un inicio en una aplicación web.

Una técnica común era cargar inicialmente imágenes de baja resolución, o incluso marcadores con elementos <div> vacíos o pseudo-elementos CSS estilizados con un color de fondo. Los eventos de desplazamiento y las posiciones de los elementos en el área de visualización del navegador se usaban para determinar cuándo se deberían cargar finalmente las imágenes de alta resolución.

Este enfoque era práctico pero requería ajustes personalizados para evitar la degradación del rendimiento web que podría incluso anular el propósito de la carga diferida. Limitar o amortiguar la captura del evento scroll de desplazamiento por la página para evitar que se ejecutara la función callback con demasiada frecuencia o depender del método requestAnimationFrame() para asegurar que nuestro código no se ejecutara más rápido que el valor óptimo de FPS de 60hz era necesario para proporcionar una experiencia decente.

Afortunadamente, para cuando Chrome v77 lanzó la tan esperada función de carga diferida nativa, otros navegadores como Opera, Edge — y meses después, Firefox y Safari — se unieron. El nuevo método era mucho más sencillo y permitía a los desarrolladores confiar en la optimización del navegador para proceder con el proceso de diferimiento de imágenes. No había ya necesidad de JavaScript adicional para implementar la funcionalidad de carga diferida.

<img src=”imagen-diferida.jpg” loading=”lazy” alt=”Descripción de la imagen”>

Pero aún necesitamos decidir qué imágenes marcar para la carga diferida y determinar los valores explícitos de sus propiedades width y height en función de sus dimensiones intrínsecas para ayudar al navegador a calcular el layout antes de recibir el contenido de la imagen y evitar cambios de diseño que impactan negativamente a la métrica CLS.

El atributo HTML decoding ofrece una capa adicional de control. Al establecer el valor a “async”, podemos instruir al navegador para descodificar y renderizar una imagen después de procesar otros recursos críticos, reduciendo aún más la aparición de posibles cambios de diseño cuando se agregan imágenes dinámicamente.

<img src=”imagen-diferida.jpg” loading=”lazy” decoding=”async” alt=”Descripción de la imagen”>

Ajustar estos atributos de forma consciente garantiza que la carga diferida no sea solo aplazar imágenes fuera de pantalla utilizando capacidades nativas del navegador, sino parte de una estrategia integral para la optimización del rendimiento en alineación con las necesidades de UX y del producto.

Condiciones del área de visualización

No podemos permitirnos ignorar las condiciones del área de visualización (viewport) al abordar una estrategia para retrasar la representación de imágenes, ya que son vitales para determinar qué imágenes se cargan y cuándo bajo qué circunstancias.

The srcset attribute — in combination with the sizes attribute — gives us control over this to allow the browsers to choose the most appropriate image file based on the user’s device conditions, like screen size and pixel density.

El atributo srcset — en combinación con el atributo sizes— nos da control sobre esto para permitir que los navegadores web elijan el fichero de imagen más apropiado en función de las condiciones tanto del dispositivo del usuario, como el tamaño de pantalla y la densidad de píxeles.

<img srcset=”imagen-480w.jpg 480w,
imagen-960w.jpg 960w,
imagen-1200w.jpg 1200w,
imagen-480w@2x.jpg 480w 2x,
imagen-960w@2x.jpg 960w 2x,
imagen-1200w@2x.jpg 1200w 2x”
sizes=”(max-width: 480px) 480px,
(max-width: 960px) 960px,
1200px”
src=”imagen-1200w.jpg” alt=”Descripción de la imagen”>

Esto minimiza la cantidad de datos innecesarios que deben descargarse y garantiza que solo las imágenes más pertinentes y optimizadas se carguen a medida que el usuario se desplaza por la página.

El elemento HTML picture ofrece aún más granularidad, permitiéndonos establecer qué archivo de imagen debe usarse en función de los media queries correspondientes. Este enfoque es muy valioso para cumplir con los requisitos de diseño visual que pueden dictar diferentes imágenes para diferentes tamaños de pantalla, orientaciones o esquemas de color.

<picture>
<!– imágenes WebP para modo oscuro y orientación horizontal en pantallas pequeñas –>
<source media=”(max-width: 480px) and (orientation: landscape) and (prefers-color-scheme: dark)”
srcset=”imagen-480w-dark-landscape.webp 480w,
imagen-480w-dark-landscape@2x.webp 480w 2x”
type=”image/webp”>
<!– imágenes WebP para modo claro y orientación horizontal en pantallas pequeñas –>
<source media=”(max-width: 480px) and (orientation: landscape) and (prefers-color-scheme: light)”
srcset=”imagen-480w-light-landscape.webp 480w,
imagen-480w-light-landscape@2x.webp 480w 2x”
type=”image/webp”>
<!– imágenes WebP para servir en otras condiciones –>
<source srcset=”imagen-480w.webp 480w,
imagen-1200w.webp 1200w,
imagen-480w@2x.webp 480w 2x,
imagen-1200w@2x.webp 1200w 2x”
sizes=”(max-width: 480px) 480px, 1200px”
type=”image/webp”>

<!– imágenes JPEG para modo oscuro y orientación horizontal en pantallas pequeñas –>
<source media=”(max-width: 480px) and (orientation: landscape) and (prefers-color-scheme: dark)”
srcset=”imagen-480w-dark-landscape.jpg 480w,
imagen-480w-dark-landscape@2x.jpg 480w 2x”
type=”image/jpeg”>

<!– imágenes JPEG para modo claro y orientación horizontal en pantallas pequeñas –>
<source media=”(max-width: 480px) and (orientation: landscape) and (prefers-color-scheme: light)”
srcset=”imagen-480w-light-landscape.jpg 480w,
imagen-480w-light-landscape@2x.jpg 480w 2x”
type=”image/jpeg”>
<!– imágenes JPEG para servir en otras condiciones –>
<source srcset=”imagen-480w.jpg 480w,
imagen-1200w.jpg 1200w,
imagen-480w@2x.jpg 480w 2x,
imagen-1200w@2x.jpg 1200w 2x”
sizes=”(max-width: 480px) 480px, 1200px”
type=”image/jpeg”>

<!– imagen de reserva –>
<img src=”imagen-1200w.jpg” alt=”Descripción de la imagen”>
</picture>

Formatos de archivo modernos como WebP y AVIF ofrecen una compresión y calidad superiores en comparación con las imágenes JPEG o PNG tradicionales. El elemento <picture> también permite que el navegador web de los usuarios seleccione el formato más adecuado y compatible para renderizar las imágenes para ellos.

En un cercano futuro, los navegadores, rastreadores web y motores de lectores de pantalla impulsados por IA podrían alcanzar un nivel en el que proporcionar texto alternativo pueda volverse innecesario, en la mayoría de los casos. Estas máquinas entrenadas podrían traducir el contenido de la imagen en texto legible para los usuarios que lo necesiten, pero si una inteligencia artificial aún no ha accedido al archivo de imagen, el valor del atributo alt aún podría ser necesario por adelantado en la declaración HTML.

Este atributo sigue siendo crucial para hacer que nuestras imágenes — las relevantes para el contenido de la página y no solo con fines estéticos — sean accesibles para los usuarios que no las consumen visualmente, y también sirve como una imagen de reserva cuando las imágenes no se pueden cargar o se aplazan intencionadamente para una representación posterior. Proporcionar un texto alternativo significativo respalda una estrategia de diferimiento de imágenes más inclusiva y efectiva.

Imágenes Optimizadas en Angular

La directiva autónoma (standalone)NgOptimizedImage, estable desde Angular 15, ha sido fundamental para difundir las mejores prácticas de renderización de imágenes, independientemente del interés del desarrollador en el ajuste del rendimiento visual.

Esta directiva integrada en Angular nos ayuda no solo a proporcionar las pistas necesarias para priorizar imágenes críticas, sino también a diferir el procesamiento de otras imágenes. El modo “lazy” se aplica a todas las imágenes que no tengan una prioridad explícitamente definida, a no ser que le otorguemos al atributo loading un valor diferente. La directiva incluso ofrece soporte a CDNs a través del proveedor ImageLoaderConfig, valores automáticos del atributo srcset en función de los tamaños de imagen disponibles y advertencias en la consola sobre distorsión de relación de aspecto e imágenes de gran tamaño en función de la dimensión del contenedor.

Rendering Images the Angular Way

Servir imágenes a través de CDNs es también relevante en la carga de imágenes que van a ser diferidas. Estos servidores pueden almacenar los archivos de imagen más cerca de la ubicación geográfica del usuario, reduciendo significativamente la latencia de la red y mejorando los resultados de la carga demorada una vez que el usuario llegue al punto de desplazamiento o se cumplan otras condiciones interactivas.

Bloques diferidos condicionalmente

La próxima versión estable de Angular 17 traerá los bloques @defer, que se pueden declarar dentro de las plantillas de componentes para habilitar contenido diferido, no solo para imágenes o rutas de la aplicación. Además del atributo loading en imágenes HTML, podremos manipular — durante la vista previa para desarrolladores de esta característica — segmentos completos del HTML.

@Component({
selector: ‘componente-contenedor’,
standalone: true,
template: `
@defer (when esVisible) {
<sub-componente />
}
`
})
class ComponenteContenedor { … }

La sintaxis de bloques deferidos va más allá de chequeos booleanos. Podemos retrasar la renderización de componentes en función de una variedad de condiciones, como un tiempo de espera específico, el estado inactivo del navegador o disparadores de eventos de JavaScript. Por ejemplo, la pausa en la renderización podría ocurrir hasta que se produzca un desplazamiento del mouse en un elemento identificado con una referencia de plantilla o hasta que ese elemento entre en el área de visualización.

@Component({
selector: ‘componente-contenedor’,
standalone: true,
template: `
@defer (on viewport(elemento)) {
<sub-componente />
}
<section #elemento style=”margin-top: 100vh”>Contenido fuera de pantalla</section>
`
})
class ComponenteContenedor { … }

Los bloques @loading y @placeholder permiten mostrar algo temporalmente durante la resolución de dependencias y mientras se está renderizando el contenido, respectivamente. Podemos usarlos para mostrar indicadores de carga, indicadores de progreso o esqueletos visuales según las restricciones técnicas y la dirección artística.

@Component({
selector: ‘componente-contenedor’,
standalone: true,
template: `
@defer (on idle) {
<sub-componente />
}
@loading {
<p>Indicador de carga…</p>
} @placeholder {
<div>Marcador</div>
} @error {
<p>Acciones correctivas:</p>
}
`
})
class ComponenteContenedor { … }

El bloque @error nos permite controlar aquellos casos en los que el contenido diferido falla al cargar, como cuando hay un problema al inyectar dependencias. Esta característica proporciona un mecanismo de reserva, permitiéndonos informar a los usuarios en esa misma área de la pantalla sobre el problema y guiarlos sobre cómo proceder, tal vez recargando el contenido o verificando su conexión a Internet.

Conclusión

Es emocionante ver cómo la integración de bloques diferidos con imágenes optimizadas y cargadas de forma diferida continuarán mejorando la velocidad de las aplicaciones y la experiencia del usuario. Este es un avance prometedor en el framework Angular para aquellos o aquellas desarrolladoras que busquen servir píxeles a la velocidad de la luz para captar la atención fugaz de los usuarios.

Los algoritmos reproducibles no pueden definir completamente el proceso de ingeniería de una experiencia de usuario óptima. El arte de retrasar el contenido web literalmente trasciende las técnicas de programación para convertirse en una estrategia que mejora el rendimiento web basado en la comprensión de los principios de diseño, la psicología humana y el propósito del contenido presentado a nuestros usuarios.

Por cierto, ¿alguien más mencionó la colaboración interdisciplinaria para tomar decisiones acerca de la carga diferida de imágenes?

The English version of this article is also available on the ng-conf blog:

The Art of Delaying Image Content

El arte de diferir imágenes was originally published in ngconf on Medium, where people are continuing the conversation by highlighting and responding to this story.

Leave a Comment

Your email address will not be published. Required fields are marked *