Categories
Rendimiento

Optimizar imágenes en WordPress: WebP, AVIF, srcset, compresión y CDN

May 17, 2023

Las imágenes suelen ser lo que más pesa en una página y, muy a menudo, el elemento que marca el LCP (Largest Contentful Paint). En este artículo te contamos cómo las optimizamos en WordPress: qué formato usar (WebP y AVIF) y qué soporta realmente WordPress y cada navegador, cómo aprovechar los tamaños que genera el núcleo con srcset y sizes, cuánto comprimir, por qué conviene servirlas desde un CDN y cómo evitar los saltos de maquetación (CLS). También repasamos errores típicos: subir fotos de 5.000 píxeles para mostrarlas a 800, reglas de .htaccess que rompen la caché, imágenes sin dimensiones y la imagen principal cargada en diferido.


Por qué merece la pena

Una imagen sin optimizar afecta a varias cosas a la vez: más bytes que descargar (especialmente en móvil), un LCP más lento cuando es la imagen principal, más consumo de ancho de banda en el servidor y, si no tiene dimensiones, saltos de contenido que empeoran el CLS. Las Core Web Vitals forman parte de las señales de experiencia de página que tiene en cuenta Google, así que el impacto no es solo para el usuario.

La buena noticia es que WordPress ya hace mucho por defecto. La mayor parte del trabajo consiste en no estropearlo y en completar lo que falta.

Elegir el formato: JPEG, PNG, WebP y AVIF

Qué formato usar para cada cosa

  • Fotografías: AVIF o WebP. Con calidad visual equivalente suelen pesar bastante menos que un JPEG. AVIF comprime más, pero codifica más lento y consume más CPU al generar las miniaturas.
  • Gráficos con transparencia, capturas o logotipos rasterizados: WebP (admite transparencia) o PNG si necesitas compatibilidad con algo muy antiguo.
  • Logotipos e iconos: SVG siempre que se pueda. Ojo: WordPress no permite subir SVG por defecto porque pueden contener código; si lo habilitas, sanea los ficheros.
  • JPEG y PNG: siguen siendo válidos como formato de origen y de reserva.

Soporte en navegadores

  • WebP funciona en todos los navegadores actuales; desde que Safari lo incorporó en 2020 ya no hace falta pensar en alternativas salvo para públicos con equipos muy antiguos.
  • AVIF se considera compatible con todos los navegadores principales desde enero de 2024, cuando Edge 121 lo activó (Chrome lo soportaba desde la versión 85, Firefox desde la 93 y Safari desde la 16.4 en escritorio).

Soporte en WordPress

  • WordPress 5.8 permite subir y usar imágenes WebP. Las miniaturas se generan en el mismo formato que el original.
  • WordPress 6.5 añade lo mismo para AVIF.
  • En ambos casos depende del servidor: la librería de imagen (Imagick o GD) tiene que soportar el formato. Lo puedes comprobar en Herramientas → Salud del sitio → Información → Gestión de medios. Si no lo soporta, la subida falla.
  • En multisitio puede que tengas que añadir los tipos de archivo permitidos en los ajustes de la red.

WordPress no convierte automáticamente los JPEG a WebP o AVIF. Hay dos formas de conseguirlo sin herramientas de terceros:

Opción A: el filtro image_editor_output_format

Con este filtro, al subir un JPEG WordPress genera los tamaños intermedios en otro formato. El original se conserva tal cual:

// Generar las miniaturas de JPEG y PNG en WebP (o 'image/avif' si el servidor lo soporta)
add_filter( 'image_editor_output_format', function ( $formats ) {
    $formats['image/jpeg'] = 'image/webp';
    $formats['image/png']  = 'image/webp';
    return $formats;
} );

Opción B: el plugin Modern Image Formats

Es el plugin del equipo de rendimiento de WordPress (antes llamado WebP Uploads). Genera AVIF si el servidor lo soporta y, si no, WebP; permite elegir el formato en Ajustes → Medios, generar también versiones de reserva en el formato original y usar el elemento <picture>. Solo actúa sobre las subidas nuevas: para las existentes hay que regenerar los tamaños (lo vemos más abajo).

Si generas las versiones fuera de WordPress

Si conviertes imágenes en local (con cwebp, avifenc, Squoosh o tu herramienta de build) y quieres ofrecer alternativa, el elemento <picture> es la forma correcta: el navegador elige el primer formato que entiende.

<picture>
  <source srcset="/img/foto.avif" type="image/avif">
  <source srcset="/img/foto.webp" type="image/webp">
  <img src="/img/foto.jpg" alt="Descripción de la imagen" width="1200" height="800">
</picture>

Una advertencia sobre una técnica muy extendida: servir el .webp en lugar del .jpg con una regla de mod_rewrite que mira la cabecera Accept. Funciona, pero la misma URL devuelve contenidos distintos según el navegador, y si no envías Vary: Accept un CDN o una caché intermedia puede guardar la versión equivocada y servirla a todo el mundo. Si la usas, la regla tiene que ir acompañada de esa cabecera:

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTP_ACCEPT} image/webp
  RewriteCond %{REQUEST_FILENAME} .(jpe?g|png)$
  RewriteCond %{REQUEST_FILENAME}.webp -f
  RewriteRule ^(.+).(jpe?g|png)$ $1.$2.webp [T=image/webp,L]
</IfModule>

<IfModule mod_headers.c>
  <FilesMatch ".(jpe?g|png|webp)$">
    Header append Vary Accept
  </FilesMatch>
</IfModule>

Hoy, con WebP universal, preferimos generar directamente las miniaturas en el formato moderno y evitar la negociación.

Tamaños, srcset y sizes

Lo que WordPress ya hace

  • Al subir una imagen, genera varios tamaños intermedios (miniatura, medio, grande y los que registre el tema con add_image_size()).
  • Desde WordPress 4.4 añade srcset y sizes a las imágenes, para que el navegador descargue el tamaño adecuado a la pantalla y la densidad de píxeles.
  • Desde WordPress 5.3, si subes una imagen de más de 2560 píxeles de ancho o alto, crea una versión reducida (con el sufijo -scaled) y la usa como imagen principal. El original se guarda aparte. El límite se cambia con el filtro big_image_size_threshold.
  • Desde WordPress 6.7, las imágenes con loading="lazy" llevan sizes="auto", de modo que el navegador elige del srcset según el ancho real de renderizado.

Lo que te toca a ti

  • No subas fotos directamente de la cámara. Redimensiónalas antes a algo razonable para tu diseño (por ejemplo, el doble del ancho máximo en que se va a mostrar, para pantallas de alta densidad).
  • Registra tamaños que coincidan con tu diseño. Si tu tarjeta de blog mide 400 px, un tamaño de 400 y otro de 800 hacen que srcset tenga opciones útiles.
  • **Ajusta sizes cuando el valor por defecto no encaja.** Por defecto WordPress usa (max-width: {ancho}px) 100vw, {ancho}px, que da por hecho que la imagen ocupa todo el ancho en pantallas pequeñas. En una rejilla de tres columnas eso hace que el móvil descargue más de lo necesario.
// Imagen de una rejilla de 3 columnas en escritorio y 1 columna en móvil
echo wp_get_attachment_image( $image_id, 'large', false, array(
    'sizes' => '(max-width: 768px) 100vw, 33vw',
) );
  • Regenera los tamaños cuando cambies add_image_size() o actives la conversión a WebP/AVIF. Con WP-CLI es un comando: wp media regenerate --only-missing. Si no usas la terminal, el plugin Regenerate Thumbnails hace lo mismo. Tienes más ejemplos de WP-CLI en este artículo sobre flujo de trabajo con WP-CLI.

Compresión

WordPress ya recomprime las imágenes que genera: la calidad por defecto de los tamaños intermedios es 82, y se puede cambiar por tipo MIME con el filtro wp_editor_set_quality:

add_filter( 'wp_editor_set_quality', function ( $quality, $mime_type ) {
    if ( 'image/avif' === $mime_type ) {
        return 60;
    }
    return $quality;
}, 10, 2 );

Ese valor es un punto de partida, no una regla: la escala de calidad no es equivalente entre formatos, así que compara visualmente antes de bajar. Otros puntos a tener en cuenta:

  • El original no se toca. El archivo que subes se conserva tal cual, con su peso y sus metadatos (EXIF, ubicación GPS, modelo de cámara). Si no quieres publicar esos datos, límpialos antes de subir.
  • Compresión con o sin pérdida. Para fotografía, la compresión con pérdida bien ajustada no se nota; la compresión sin pérdida tiene sentido para gráficos, capturas o imágenes donde cada píxel importa.
  • Plugins de compresión. Smush, EWWW Image Optimizer, ShortPixel o Imagify automatizan la compresión al subir y pueden procesar la biblioteca existente. Algunos comprimen en tu servidor y otros envían las imágenes a un servicio externo; revisa cuál es el caso y sus límites antes de activarlos en una biblioteca grande.

Dimensiones: evitar el CLS

Si una imagen no tiene width y height, el navegador no sabe cuánto espacio reservar hasta que la descarga, y todo lo que hay debajo se desplaza. Los navegadores actuales calculan la proporción a partir de esos atributos, así que basta con ponerlos y dejar que el CSS haga la imagen fluida:

img {
  max-width: 100%;
  height: auto;
}

WordPress añade width y height a las imágenes de la biblioteca de medios cuando faltan en el contenido. Donde suele fallar es en imágenes escritas a mano en plantillas, en fondos CSS y en bloques de constructores visuales. Para contenedores con imágenes de fondo o incrustaciones, reserva el espacio con aspect-ratio:

.hero {
  aspect-ratio: 16 / 9;
  background-size: cover;
}

Lazy load, sí, pero no en la imagen principal

WordPress añade loading="lazy" a las imágenes del contenido desde la versión 5.5, deja sin diferir las primeras y, desde la 6.3, marca con fetchpriority="high" la que considera candidata a LCP. Ya no hace falta un plugin solo para esto. Lo que sí hay que revisar es que la imagen del hero o la imagen destacada no acabe en diferido por culpa del tema o de un plugin de optimización. Lo explicamos en detalle, con ejemplos para fondos CSS y componentes, en cómo usar el lazy load con loading=»lazy» e IntersectionObserver.

Servir las imágenes desde un CDN

Un CDN guarda copias de tus ficheros estáticos en servidores repartidos geográficamente, así que las imágenes llegan desde un punto cercano al usuario y tu servidor deja de servir ese tráfico. Algunas recomendaciones:

  • Cabeceras de caché largas. Las imágenes de wp-content/uploads casi nunca cambian de contenido con la misma URL, así que admiten un Cache-Control de larga duración.
  • CDN de imágenes. Algunos servicios redimensionan y convierten a WebP o AVIF al vuelo según el navegador. Es cómodo, pero revisa que respeten la cabecera Vary o que usen URLs distintas por formato, y ten en cuenta el coste por transformación.
  • No dupliques trabajo. Si el CDN ya convierte formatos, no tiene sentido que un plugin genere además versiones WebP en el servidor.

Si usas Cloudflare, tienes la configuración que aplicamos en acelerar WordPress con Cloudflare. Este blog, por cierto, es un WordPress headless con Gatsby desplegado en Netlify, donde el front y sus estáticos se sirven desde la CDN del propio hosting.

Texto alternativo y nombres de archivo

No afectan al rendimiento, pero forman parte de publicar bien una imagen:

  • **Atributo alt**: describe lo que muestra la imagen para quien usa un lector de pantalla. Si es decorativa, alt="". No lo uses para meter palabras clave.
  • Nombre de archivo: mejor equipo-reunion-oficina.jpg que IMG_0012.jpg. Ayuda a ordenar la biblioteca y da contexto a los buscadores.

Cómo comprobar el resultado

  • PageSpeed Insights (o Lighthouse en Chrome DevTools) te dice cuál es el elemento LCP, si se ha cargado en diferido y qué imágenes podrían servirse en un formato más ligero o con un tamaño más ajustado.
  • El panel Network de DevTools, filtrando por imágenes, muestra el formato y el peso que llega realmente al navegador. Es la forma rápida de confirmar que se está sirviendo WebP o AVIF y no el JPEG original.
  • Los datos de campo (el informe de Core Web Vitals de Search Console o la sección de experiencia real de PageSpeed Insights) son los que cuentan: el laboratorio sirve para diagnosticar, pero el LCP y el CLS que importan son los de tus usuarios.

Resumen

  • Fotografías en AVIF o WebP; WordPress soporta WebP desde 5.8 y AVIF desde 6.5 si el servidor lo permite.
  • Redimensiona antes de subir y deja que srcset y sizes hagan su trabajo; ajusta sizes en rejillas.
  • Comprime con criterio y limpia los metadatos del original.
  • Todas las imágenes con dimensiones o aspect-ratio.
  • Lazy load en todo lo que está por debajo del primer pantallazo, nunca en la imagen LCP.
  • CDN con caché larga y cuidado con la negociación de formatos.

Tags:
Equipo Èmfasi

Escrito por Equipo Èmfasi

Artículos del equipo de desarrollo de Èmfasi.

GM Coders
Blog sobre el desarrollo de sitios web rápidos y optimizados