Web Performance: Imágenes
Tags: webdev, performance, spanish
Published: 2022-07-18 10:39:18

Las imágenes representan al rededor del 50% del ancho de banda de un sitio web ([ref.](https://developer.mozilla.org/en-US/docs/Learn/Performance/Multimedia)), por eso es que en este artículo vamos a hablar de ellas.

Veamos algunos puntos a tener en cuenta.

## ¿Realmente necesitas una imagen ahí?

**Una imagen vale más que mil palabras**. Seguramente escuchaste esa frase, y es una gran verdad, como también lo es el hecho de que un diseño simple y concreto transmite mejor lo que queremos decir, y performa mejor 😉.

Entonces, lo primero que debemos preguntarnos (o preguntarle a nuestros diseñadores) es si ese componente necesita de forma imperativa una imagen para funcionar.

Tal vez esa imagen podría ser reemplazada por un color plano, o un gradiente, y en ambos casos podríamos generar esto con CSS y ahorrarnos un montón de bytes de esa imagen.

Ojo, no estoy diciendo que elimines todas las imágenes de tu sitio web, sino que encuentres un equilibro entre el uso de las mismas y otros recursos.

Si luego de analizar las alternativas, llegas a la conclusión de que si o si necesitas una imagen ahí, perfecto, ¡tienes mucho trabajo que hacer!

## Formatos

Cuando decidimos trabajar con imágenes, es muy importante que definamos el formato de la misma. Veamos algunos formatos y sus características:

- **JPG**: se trata de un formato de imágenes optimizado. Tiene perdida de calidad.
- **PNG**: se trata de un formato que además de admitir transparencias preserva la calidad de la imagen, pero suelen ser archivos muy pesados.
- **WebP**: se trata de un formato relativamente moderno que fue impulsado por Google. Este formato acepta transparencias, no tiene perdida de calidad y se trata de archivos muy pequeños. Es el formato altamente recomendado y ya la mayoría de los browsers lo implementan. [Ver compatibilidad](https://caniuse.com/webp).

Para asegurarte de que todos tus usuarios van a visualizar correctamente las imágenes, incluso los que visiten el sitio desde navegadores antiguos, puedes darle opciones de carga al browser mediante la etiqueta `<picture>` de la siguiente manera:

```html
<picture>
  <source
    srcset="gatitos.webp"
    type="image/webp"
  />
  <source
    srcset="gatitos.jpg"
    type="image/jpg"
  />
  <img
    src="gatitos.jpg"
    alt="Gatitos jugando con una pelota."
    {* ¡SPOILER ALERT! *}
    loading="lazy" 
  />
</picture>
```

Dimensiones

Cómo las imágenes se cargan de forma asincrónica y continúan cargándose después de la primera pintura del DOM, si sus dimensiones no se definen antes de la carga, pueden provocar saltos o "reflujos" en el contenido de la página. Y esto tiene dos implicancias negativas:

- El navegador debe volver a pintar el DOM y a realizar nuevos cálculos de los elementos que están a continuación de la imagen cargada.
- Estos saltos son molestos para el usuario y generan una mala experiencia.

Ejemplos:
![Imagen sin definición de tamaños genera "reflow" en el contenido.](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c9nhmh2f03bt1wf5wlai.gif)
_Imagen sin definición de tamaños genera "reflow" en el contenido._

![Imagen con tamaños definidos no genera "reflow".](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdghyoc6f0icox2qpfoa.gif)
_Imagen con tamaños definidos no genera "reflow"._

## Carga diferida
Supongamos que nuestra página tiene tanto contenido que el usuario necesita hacer varios scrolls antes de llegar al final de la misma. Supongamos también que el usuario al ingresar, hizo click en alguna de las opciones del menú y navegó hacía otra página.

Entonces las imágenes que están en los componentes que solo se visualizan al hacer scroll el usuario nunca las vio, pero las tuvo que descargar igual, ¿no? Hm 🤔.

Para resolver este problema es qué tenemos que hacer uso de la carga diferida de imágenes, es decir, indicarle al browser que cargue las imágenes solo si el usuario las necesita. ¿Cómo hacemos esto? Tenemos dos maneras:

- Los navegadores modernos ([ver compatibilidad](https://caniuse.com/loading-lazy-attr)) implementan de forma nativa la carga diferida de imágenes, y para esto debemos usar el atributo `<img loading="lazy" src="gatitos.jpg" alt="Gatitos jugando con una pelota" />`. De esta manera, el browser solo cargará dicha imagen cuando el usuario se encuentre cerca de ella.
- Haciendo uso de la API del navegador **Interserction Observer**, la cual nos permite hacer lo mismo que el punto anterior pero "programáticamente". Te dejo un link para que veas la [documentación de esta API](https://developer.mozilla.org/es/docs/Web/API/Intersection_Observer_API).

## CSS
Muchas veces usamos imágenes como fondos desde CSS. No está mal hacer eso, en absoluto, pero te dejo algunas recomendaciones a tener en cuenta para cuando lo hagas:

- El browser asigna una prioridad de carga más alta a las imágenes referenciadas en elementos `<img>` que las imágenes referenciadas desde CSS.
- Las imágenes referenciadas desde CSS son invisibles a los lectores de pantalla, por lo tanto dichas imágenes no existirán para algunos usuarios.
- Si el navegador ha determinado que una regla CSS que involucra un recurso externo no se aplica al documento como está construido actualmente, el navegador no lo solicita. Es decir, si defines una imagen dentro de una media query, esta solo se cargará cuando se aplique esa regla.

Y eso es todo por ahora, nos vemos pronto 👋🏻.