Las imágenes suelen ser el recurso más pesado y más frecuente en la Web. Como resultado, optimizar las imágenes puede mejorar significativamente el rendimiento de tu sitio web. En la mayoría de los casos, optimizar las imágenes significa reducir el tiempo de red enviando menos bytes, pero también puedes optimizar la cantidad de bytes enviados al usuario publicando imágenes con el tamaño adecuado para su dispositivo.
Las imágenes se pueden agregar a una página con los elementos <img>
o <picture>
, o con la propiedad background-image
de CSS.
Tamaño de la imagen
La primera optimización que puedes realizar cuando se trata de usar recursos de imagen es mostrar la imagen con el tamaño correcto. En este caso, el término tamaño hace referencia a las dimensiones de una imagen. Sin considerar otras variables, una imagen que se muestra en un contenedor de 500 píxeles por 500 píxeles tendría un tamaño óptimo de 500 píxeles por 500 píxeles. Por ejemplo, usar una imagen cuadrada de 1,000 píxeles significa que la imagen es el doble de grande de lo necesario.
Sin embargo, hay muchas variables involucradas en la elección del tamaño de imagen adecuado, lo que hace que la tarea de elegir el tamaño de imagen adecuado en cada caso sea bastante complicada. En 2010, cuando se lanzó el iPhone 4, la resolución de la pantalla (640 x 960) era el doble de la del iPhone 3 (320 x 480). Sin embargo, el tamaño físico de la pantalla del iPhone 4 siguió siendo casi el mismo que el del iPhone 3.
Mostrar todo en la resolución más alta habría hecho que el texto y las imágenes fueran significativamente más pequeños, la mitad de su tamaño anterior para ser exactos. En cambio, 1 píxel se convirtió en 2 píxeles del dispositivo. Esto se denomina proporción de píxeles del dispositivo (DPR). El iPhone 4, y muchos modelos de iPhone lanzados después de él, tenían un DPR de 2.
Si retomamos el ejemplo anterior, si el dispositivo tiene un DPR de 2 y la imagen se muestra en un contenedor de 500 píxeles por 500 píxeles, el tamaño óptimo ahora es una imagen cuadrada de 1,000 píxeles (denominada tamaño intrínseco). Del mismo modo, si el dispositivo tiene un DPR de 3, el tamaño óptimo sería una imagen cuadrada de 1,500 píxeles.
srcset
El elemento <img>
admite el atributo srcset
, que te permite especificar una lista de posibles fuentes de imágenes que el navegador puede usar. Cada fuente de imagen especificada debe incluir la URL de la imagen y un descriptor de densidad de píxeles o ancho.
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
srcset="/image-500.jpg 1x, /image-1000.jpg 2x, /image-1500.jpg 3x"
>
El fragmento de HTML anterior usa el descriptor de densidad de píxeles para sugerirle al navegador que use image-500.png
en dispositivos con una DPR de 1, image-1000.jpg
en dispositivos con una DPR de 2 y image-1500.jpg
en dispositivos con una DPR de 3.
Si bien todo esto puede parecer sencillo, el DPR de una pantalla no es la única consideración para elegir la imagen óptima para una página determinada. El diseño de la página es otro aspecto que se debe tener en cuenta.
sizes
La solución anterior solo funciona si muestras la imagen con el mismo tamaño de píxeles CSS en todos los puertos de visualización. En muchos casos, el diseño de una página, y el tamaño del contenedor con él, cambia según el dispositivo del usuario.
El atributo sizes
te permite especificar un conjunto de tamaños de origen, en el que cada tamaño de origen consta de una condición de medios y un valor. El atributo sizes
describe el tamaño de visualización previsto de la imagen en píxeles de CSS. Cuando se combinan con los descriptores de ancho srcset
, el navegador puede elegir qué fuente de imagen es mejor para el dispositivo del usuario.
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
srcset="/image-500.jpg 500w, /image-1000.jpg 1000w, /image-1500.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
En el fragmento de HTML anterior, el atributo srcset
especifica una lista de imágenes candidatas entre las que el navegador puede elegir, separadas por comas. Cada candidato de la lista consta de la URL de la imagen, seguida de una sintaxis que denota el ancho intrínseco de la imagen. El tamaño intrínseco de una imagen son sus dimensiones. Por ejemplo, un descriptor de 1000w
indica que el ancho intrínseco de la imagen es de 1,000 píxeles.
Con esta información, el navegador evalúa la condición de medios en el atributo sizes
y, en este caso, se le indica que, si el ancho del viewport del dispositivo supera los 768 píxeles, la imagen se mostrará con un ancho de 500 píxeles. En dispositivos más pequeños, la imagen se muestra en 100vw
, o bien en todo el ancho de la ventana gráfica.
Luego, el navegador puede combinar esta información con la lista de fuentes de imágenes srcset
para encontrar la imagen óptima. Por ejemplo, si el usuario está en un dispositivo móvil con un ancho de pantalla de 320 píxeles y un DPR de 3, la imagen se muestra en 320 CSS pixels x 3 DPR = 960 device pixels
. En este ejemplo, la imagen de tamaño más cercano sería image-1000.jpg
, que tiene un ancho intrínseco de 1,000 píxeles (1000w
).
Formatos de archivo
Los navegadores admiten varios formatos de archivo de imagen diferentes. Los formatos de imagen modernos, como WebP y AVIF, pueden proporcionar una mejor compresión que PNG o JPEG, lo que reduce el tamaño del archivo de imagen y, por lo tanto, el tiempo de descarga. Si publicas imágenes en formatos modernos, puedes reducir el tiempo de carga de un recurso, lo que puede generar un Procesamiento de imagen con contenido más grande (LCP) más bajo.
WebP es un formato ampliamente compatible que funciona en todos los navegadores modernos. WebP suele tener una mejor compresión que JPEG, PNG o GIF, y ofrece compresión con pérdida y sin pérdida. WebP también admite la transparencia del canal alfa, incluso cuando se usa la compresión con pérdida, una función que el códec JPEG no ofrece.
AVIF es un formato de imagen más nuevo y, si bien no es tan compatible como WebP, sí se admite de forma razonablemente decente en todos los navegadores. AVIF admite la compresión con pérdida y sin pérdida, y las pruebas demostraron que, en algunos casos, se ahorra más del 50% en comparación con JPEG. AVIF también ofrece funciones de amplia gama de colores (WCG) y alto rango dinámico (HDR).
Compresión
En el caso de las imágenes, existen dos tipos de compresión:
La compresión con pérdidas funciona reduciendo la precisión de la imagen a través de la cuantificación, y se puede descartar información de color adicional con el submuestreo de crominancia. La compresión con pérdida es más eficaz en imágenes de alta densidad con mucho ruido y colores, por lo general, fotos o imágenes con contenido similar. Esto se debe a que es mucho menos probable que se noten los artefactos producidos por la compresión con pérdida en imágenes tan detalladas. Sin embargo, la compresión con pérdida puede ser menos eficaz con imágenes que contienen bordes definidos, como arte lineal, detalles igualmente nítidos o texto. La compresión con pérdida se puede aplicar a imágenes en formato JPEG, WebP y AVIF.
La compresión sin pérdida reduce el tamaño del archivo comprimiendo una imagen sin pérdida de datos. La compresión sin pérdida describe un píxel en función de la diferencia con sus píxeles vecinos. La compresión sin pérdida se usa para los formatos de imagen GIF, PNG, WebP y AVIF.
Puedes comprimir tus imágenes con Squoosh, ImageOptim o un servicio de optimización de imágenes. Cuando se comprime, no hay un parámetro de configuración universal adecuado para todos los casos. El enfoque recomendado sería experimentar con diferentes niveles de compresión hasta que encuentres un buen equilibrio entre la calidad de la imagen y el tamaño del archivo. Algunos servicios avanzados de optimización de imágenes pueden hacerlo automáticamente, pero es posible que no sean viables económicamente para todos los usuarios.
El elemento <picture>
El elemento <picture>
te brinda mayor flexibilidad para especificar varias imágenes candidatas:
<picture>
<source type="image/avif" srcset="image.avif">
<source type="image/webp" srcset="image.webp">
<img
alt="An image"
width="500"
height="500"
src="/image.jpg"
>
</picture>
Cuando usas elementos <source>
dentro del elemento <picture>
, puedes agregar compatibilidad con imágenes AVIF y WebP, pero volver a formatos de imagen heredados más compatibles si el navegador no admite formatos modernos. Con este enfoque, el navegador elige el primer elemento <source>
especificado que coincida. Si puede renderizar la imagen en ese formato, la usa. De lo contrario, el navegador pasará al siguiente elemento <source>
especificado. En el fragmento de HTML anterior, el formato AVIF tiene prioridad sobre el formato WebP y se recurre al formato JPEG si no se admite AVIF ni WebP.
Un elemento <picture>
requiere un elemento <img>
anidado dentro de él. Los atributos alt
, width
y height
se definen en <img>
y se usan independientemente del <source>
que se seleccione.
El elemento <source>
también admite los atributos media
, srcset
y sizes
. Al igual que en el ejemplo de <img>
anterior, estos indican al navegador qué imagen seleccionar en diferentes ventanas gráficas.
<picture>
<source
media="(min-resolution: 1.5x)"
srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
>
</picture>
El atributo media
toma una condición de medios. En el ejemplo anterior, el DPR del dispositivo se usa como condición de medios. Cualquier dispositivo con un DPR mayor o igual a 1.5 usaría el primer elemento <source>
. El elemento <source>
le indica al navegador que, en dispositivos con un viewport más ancho que 768 píxeles, la imagen candidata seleccionada se muestra con un ancho de 500 píxeles. En dispositivos más pequeños, ocupa todo el ancho del viewport. Si combinas los atributos media
y srcset
, puedes tener un mayor control sobre qué imagen usar.
Esto se ilustra en la siguiente tabla, en la que se evalúan varios anchos de viewport y relaciones de píxeles del dispositivo:
Ancho del viewport (píxeles) | 1 DPR | 1.5 DPR | 2 DPR | 3 DPR |
---|---|---|---|---|
320 | 500.jpg | 500.jpg | 500.jpg | 1000.jpg |
480 | 500.jpg | 500.jpg | 1000.jpg | 1500.jpg |
560 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
1024 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
1920 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
Los dispositivos con un DPR de 1 descargan la imagen image-500.jpg
, incluidos la mayoría de los usuarios de computadoras, que ven la imagen con un tamaño extrínseco de 500 píxeles de ancho. Por otro lado, los usuarios de dispositivos móviles con un DPR de 3 descargan un image-1500.jpg
potencialmente más grande, la misma imagen que se usa en dispositivos de escritorio con un DPR de 3.
<picture>
<source
media="(min-width: 561px) and (min-resolution: 1.5x)"
srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
<source
media="(max-width: 560px) and (min-resolution: 1.5x)"
srcset="/image-1000-sm.jpg 1000w, /image-1500-sm.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
>
</picture>
En este ejemplo, el elemento <picture>
se ajusta para incluir un elemento <source>
adicional que permita usar diferentes imágenes para dispositivos anchos con un DPR alto:
Ancho del viewport (píxeles) | 1 DPR | 1.5 DPR | 2 DPR | 3 DPR |
---|---|---|---|---|
320 | 500.jpg | 500.jpg | 1000-sm.jpg | 1000-sm.jpg |
480 | 500.jpg | 500.jpg | 1000-sm.jpg | 1500-sm.jpg |
560 | 500.jpg | 1000-sm.jpg | 1000-sm.jpg | 1500-sm.jpg |
1024 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
1920 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
Con esta consulta adicional, puedes ver que image-1000-sm.jpg
y image-1500-sm.jpg
se muestran en ventanas gráficas pequeñas. Esta información adicional te permite comprimir aún más las imágenes, ya que los artefactos de compresión no son muy visibles en ese tamaño y densidad, y no se compromete la calidad de la imagen en los dispositivos de escritorio.
También puedes ajustar los atributos srcset
y media
para evitar publicar imágenes grandes en ventanas gráficas pequeñas:
<picture>
<source
media="(min-width: 561px)"
srcset="/image-500.jpg, /image-1000.jpg 2x, /image-1500.jpg 3x"
>
<source
media="(max-width: 560px)"
srcset="/image-500.jpg 1x, /image-1000.jpg 2x"
>
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
>
</picture>
En el fragmento de HTML anterior, se quitaron los descriptores de ancho y se reemplazaron por descriptores de proporción de píxeles del dispositivo. Las imágenes que se publican en dispositivos móviles se limitan a /image-500.jpg
o /image-1000.jpg
, incluso en dispositivos con un DPR de 3.
Cómo administrar la complejidad
Cuando trabajas con imágenes responsivas, puedes encontrarte con muchas variaciones de tamaño y formatos diferentes para cada imagen. En el ejemplo anterior, se usan variaciones para cada tamaño, pero se excluyen AVIF y WebP. ¿Cuántas variantes deberías tener? Al igual que con muchos problemas de ingeniería, la respuesta suele ser "depende".
Si bien puede ser tentador tener tantas variantes como sea posible para ofrecer el mejor ajuste, cada variante de imagen adicional tiene un costo y hace que el uso de la caché del navegador sea menos eficiente. Con una sola variante, todos los usuarios reciben la misma imagen, por lo que se puede almacenar en caché de manera muy eficiente.
Por otro lado, si hay muchas variaciones, cada una requiere otra entrada de caché. Los costos del servidor pueden aumentar y el rendimiento puede disminuir si venció la entrada de caché de la variante y la imagen debe recuperarse nuevamente del servidor de origen.
Además de esto, el tamaño de tu documento HTML aumenta con cada variación. Podrías terminar enviando varios kilobytes de HTML por cada imagen.
Entrega imágenes según el encabezado de solicitud Accept
El encabezado de solicitud HTTP Accept
informa al servidor qué tipos de contenido comprende el navegador del usuario. Tu servidor puede usar esta información para entregar el formato de imagen óptimo sin agregar bytes adicionales a tus respuestas HTML.
if (request.headers.accept) {
if (request.headers.accept.includes('image/avif')) {
return reply.from('image.avif');
} else if (request.headers.accept.includes('image/webp')) {
return reply.from('image.webp');
}
}
return reply.from('image.jpg');
El fragmento de HTML anterior es una versión simplificada del código que puedes agregar al backend de JavaScript de tu servidor para elegir y publicar el formato de imagen óptimo.
Si el encabezado de la solicitud Accept
incluye image/avif
, se entrega la imagen AVIF. De lo contrario, si el encabezado Accept
incluye image/webp
, se entrega la imagen WebP. Si no se cumple ninguna de estas condiciones, se publicará la imagen JPEG.
Puedes modificar las respuestas según el contenido del encabezado de solicitud Accept
en casi todos los tipos de servidores web. Por ejemplo, puedes reescribir solicitudes de imágenes en servidores Apache según el encabezado Accept
con mod_rewrite
.
Esto no es diferente del comportamiento que encontrarías en una red de distribución de contenidos (CDN) de imágenes. Las CDN de imágenes son soluciones excelentes para optimizar imágenes y enviar el formato óptimo según el dispositivo y el navegador del usuario.
La clave es encontrar un equilibrio, generar una cantidad razonable de imágenes candidatas y medir el impacto en la experiencia del usuario. Las diferentes imágenes pueden generar resultados distintos, y las optimizaciones que se aplican a cada imagen dependen de su tamaño en la página y de los dispositivos que usan tus usuarios. Por ejemplo, una hero image de ancho completo puede requerir más variantes que las imágenes en miniatura en una página de ficha de producto de comercio electrónico.
Carga diferida
Es posible indicarle al navegador que cargue imágenes de forma diferida cuando aparezcan en el viewport con el atributo loading
. Un valor de atributo de lazy
le indica al navegador que no descargue la imagen hasta que esté en la ventana gráfica (o cerca de ella). Esto ahorra ancho de banda y permite que el navegador priorice los recursos que necesita para renderizar el contenido crítico que ya está en la ventana gráfica.
decoding
El atributo decoding
le indica al navegador cómo debe decodificar la imagen. Un valor de async
le indica al navegador que la imagen se puede decodificar de forma asíncrona, lo que podría mejorar el tiempo de renderización de otro contenido. Un valor de sync
le indica al navegador que la imagen se debe presentar al mismo tiempo que otro contenido.
El valor predeterminado de auto
permite que el navegador decida qué es mejor para el usuario.
Demostraciones de imágenes
Ponga a prueba sus conocimientos
¿Qué formatos de imagen admiten la compresión sin pérdidas?
¿Qué formatos de imagen admiten la compresión con pérdida?
¿Qué le indica el descriptor de ancho (por ejemplo, 1000w
) al navegador sobre una opción de imagen especificada en un atributo srcset
?
¿Qué le indica el atributo sizes
al navegador sobre un elemento <img>
al que se aplica?
srcset
de un elemento <img>
se debe cargar, teniendo en cuenta las dimensiones de la ventana gráfica actual del usuario.
srcset
del elemento <img>
.
A continuación: Rendimiento del video
Si bien las imágenes pueden ser el tipo de medio más frecuente que se usa en la Web, no son el único que debes tener en cuenta cuando se trata del rendimiento. El video es otro tipo de medio común que se usa en la Web y tiene sus propias consideraciones de rendimiento. En el próximo módulo de este curso, explora algunas técnicas para optimizar videos y cargarlos de manera eficiente.