Una web puede parecer rápida cuando la abrimos desde nuestro ordenador con una buena conexión, pero la experiencia cambia bastante cuando la visitamos desde un móvil y usando datos. Al analizar el rendimiento de mi web usando Wakaris en un dispositivo de gama media con conexión 4G apareció un problema bastante claro: el contenido principal tardaba 7,7 segundos en mostrarse. Es un tiempo suficientemente alto como para que muchos usuarios abandonen la página antes incluso de empezar a leer. En este artículo veremos qué métricas estaban afectando al rendimiento, cómo interpretarlas y, sobre todo, qué cambios podemos aplicar para intentar reducir el LCP desde esos 7,7 segundos hasta los 2,5 segundos o menos recomendados. Vamos a ver como optimizar WordPress y mejorar el LCP de nuestra web.
Tabla de contenidos
- 0. Métricas y valores iniciales
- 1. Optimizar la imagen de fondo
- 2. Descubriendo que CloudFront no comprimía la página principal
- 3. El problema estaba también en Nginx
- 4. Gzip funcionaba… pero solo en HTTP
- 5. Verificando gzip directamente contra Elastic Beanstalk
- 6. Verificando el recorrido completo con CloudFront
- 7. Diferir JQuery
- 8. Ampliar la caché a un año
- 9. Cambiando
font-display: blockporswap - 10. Resultado
0. Las métricas y valores iniciales
Vamos a explicar que es cada métrica
LCP – Largest Contentful Paint: mide cuánto tarda en mostrarse el elemento de contenido más grande visible al cargar la página, normalmente una imagen, un banner o un bloque grande de texto. Es una forma de medir cuándo el usuario siente que “la página ya ha cargado”. Como referencia, se considera bueno estar en ≤ 2,5 s.
TBT – Total Blocking Time: mide cuánto tiempo queda bloqueado el hilo principal del navegador por tareas largas, normalmente causadas por JavaScript. Mientras está bloqueado, la web puede verse cargada pero responder tarde a clics, scrolls o interacciones. Cuanto más bajo, mejor; ≤ 200 ms suele considerarse un buen objetivo en herramientas como Lighthouse.
CLS – Cumulative Layout Shift: mide cuánto se mueven inesperadamente los elementos de la página mientras carga. Por ejemplo, estás a punto de pulsar un botón y aparece una imagen arriba que desplaza todo hacia abajo. Lo ideal es un valor de ≤ 0,1.
Encontré por Linkedin hace poco una post aleatorio de un usuario que hablaba de una web de medición de rendimiento, llamada Wakaris y me gustó bastante. Y la he usado para ir iterando. Es algo similar a GTMetrix o Google PageSpeed Insights Y los resultados eran muy malos. Y en varios campos, no solo en el rendimiento. Inicialmente tuve estos resultados.
LCP 7,7
TBT 64 ms
CLS 0,01

Rendimiento, era uno de los peores valores de todo el análisis.
Antes de entrar al fondo, unas consideraciones generales para mejorar el rendimiento.
- Optimizar las imágenes: reducir dimensiones, comprimirlas y utilizar formatos modernos como WebP o AVIF.
- Evitar plugins innecesarios: cada plugin puede añadir CSS, JavaScript, consultas a base de datos o peticiones externas.
- Configurar caché: evitar que WordPress tenga que generar la misma página desde cero en cada visita.
- Usar una CDN: especialmente útil para servir imágenes, CSS, JavaScript y otros recursos estáticos.
- Reducir CSS y JavaScript: minimizar archivos, eliminar código no utilizado y evitar cargar scripts donde no hacen falta.
- Retrasar recursos no críticos: usar
defer,asynco carga diferida cuando tenga sentido. - Aplicar lazy loading: cargar imágenes y otros elementos solo cuando el usuario se acerca a ellos.
- Limitar scripts de terceros: analytics, publicidad, fuentes externas, widgets o embeds pueden penalizar mucho el rendimiento.
- Mantener WordPress, PHP y plugins actualizados: además de seguridad, las nuevas versiones suelen incluir mejoras de rendimiento.
- Revisar el servidor: CPU, memoria, almacenamiento, versión de PHP y configuración de la base de datos también influyen.
- Reducir redirecciones y peticiones HTTP: cada salto y cada recurso adicional añade latencia.
1. Optimizar la imagen de fondo
Analizando una grabación de Safari apareció rápidamente uno de los recursos más pesados de la página:
fondo.jpg
394675 bytes
Era la imagen que utilizo como fondo general del blog.
La imagen estaba en JPG, con resolución 1920×1080 y pesaba aproximadamente 395 KB.
La primera optimización fue muy sencilla: convertirla a WebP, manteniendo una calidad visual suficiente.
El resultado:
ANTES
fondo.jpg
~395 KB
DESPUÉS
fondo.webp
~187 KB
Es prácticamente la mitad de datos para mostrar exactamente el mismo fondo.
Después del cambio, Safari confirmó que la nueva imagen estaba siendo utilizada:
Content-Type: image/webp
Content-Length: 187212
No era suficiente para explicar por sí sola un LCP de 7,7 segundos, pero sí era una optimización evidente que merecía la pena hacer.
2. Descubriendo que CloudFront no comprimía la página principal
El siguiente paso fue revisar cuánto pesaba realmente el HTML.
Con curl:
curl -sS \
-H 'Accept-Encoding: br, gzip' \
-D /tmp/before-headers.txt \
-o /dev/null \
-w 'download=%{size_download} bytes\nttfb=%{time_starttransfer}s\ntotal=%{time_total}s\n' \
https://www.rubenortiz.es/El resultado era:
download=108015 bytes
ttfb=0.399917s
total=0.518430sEs decir, la home transfería alrededor de 108 KB de HTML.
Revisando los headers había otro detalle importante: no aparecía ningún:
Content-Encoding: gzip
ni:
Content-Encoding: br
CloudFront estaba entregando el HTML sin compresión.
Configuración de CloudFront
Revisando Terraform encontré que los behaviors específicos ya tenían compresión:
compress = true
Por ejemplo:
ordered_cache_behavior {
path_pattern = "/wp-content/uploads/*"
...
compress = true
}Sin embargo, faltaba precisamente en el behavior principal:
default_cache_behavior {
...
}La solución fue añadir:
compress = trueQuedando:
default_cache_behavior {
...
compress = true
viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}Después del terraform apply comprobé la compresión usando un CSS generado por Autoptimize.
Antes tenía un tamaño de aproximadamente:
271802 bytes
La prueba:
curl -sS \
-H 'Accept-Encoding: gzip' \
-D /tmp/css-compress-test.txt \
-o /dev/null \
-w 'download=%{size_download} bytes\n' \
'https://www.rubenortiz.es/wp-content/cache/autoptimize/css/autoptimize_xxx.css?cf-compress-test=1'devolvió:
content-type: text/css
content-encoding: gzip
x-cache: Miss from cloudfront
download=45685 bytesPor tanto:
CSS
~272 KB → ~46 KB
Una reducción de aproximadamente el 83 %.
CloudFront estaba comprimiendo correctamente.
Pero el HTML seguía sin hacerlo.
3. El problema estaba también en Nginx
Probé entonces directamente contra Elastic Beanstalk, evitando completamente CloudFront:
curl -ks \
-H 'Accept-Encoding: gzip' \
-D - \
-o /dev/null \
'https://mi-entorno.region.elasticbeanstalk.com/'La respuesta era:
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunkedPero seguía sin aparecer:
Content-Encoding: gzipPor tanto, Nginx tampoco estaba comprimiendo las respuestas dinámicas de WordPress.
Añadí configuración gzip:
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types
text/plain
text/css
application/json
application/javascript
application/x-javascript
text/xml
application/xml
application/xml+rss
text/javascript
image/svg+xml;Pero inicialmente seguía sin funcionar.
Aquí apareció uno de los detalles más interesantes del debugging.
4. Gzip funcionaba… pero solo en HTTP
Al inspeccionar la configuración efectiva:
sudo nginx -T 2>&1 | grep -nE 'listen .*443|listen .*80|server_name'obtuve:
114: listen 80 default_server;
1168: listen 443 ssl;
1170: server_name www.rubenortiz.es;Y al revisar dónde se encontraba gzip on:
sudo nginx -T 2>&1 | sed -n '100,150p'aparecía:
server {
listen 80 default_server;
...
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 1024;
...
}Ahí estaba el error.
La configuración gzip estaba dentro del server que escuchaba en puerto 80.
Pero tenía otro bloque independiente para HTTPS:
server {
listen 443 ssl;
server_name www.rubenortiz.es;
...
}Por tanto, el servidor de puerto 443 no heredaba esa configuración.
La solución fue mover gzip a la configuración global de Nginx mediante:
.platform/nginx/conf.d/gzip.conf
De esa manera las directivas quedan dentro de http {} y las heredan tanto el servidor HTTP como el HTTPS:
http
├── gzip on
│
├── server :80
│
└── server :443
Después validé y recargué Nginx:
sudo nginx -t && sudo systemctl reload nginx
5. Verificando gzip directamente contra Elastic Beanstalk
Primero probé nuevamente el CSS:
curl -ks --http1.1 \
-H 'Accept-Encoding: gzip' \
-D - \
-o /dev/null \
'https://mi-entorno.region.elasticbeanstalk.com/file.css'Ahora sí:
HTTP/1.1 200 OK
Content-Type: text/css
Vary: Accept-Encoding
Content-Encoding: gzipDespués llegó la prueba realmente importante: el HTML de WordPress.
curl -ks --http1.1 \<br> -H 'Accept-Encoding: gzip' \<br> -D - \<br> -o /dev/null \<br> -w 'download=%{size_download} bytes\nttfb=%{time_starttransfer}s\ntotal=%{time_total}s\n' \<br> 'https://mi-entorno.region.elasticbeanstalk.com/'Resultado:
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Vary: Accept-Encoding
Content-Encoding: gzip
download=21947 bytes
ttfb=0.803649s
total=0.879924sEl HTML había pasado de aproximadamente:
108 KB
a:
22 KB
Una reducción cercana al 80 %.
6. Verificando el recorrido completo con CloudFront
Faltaba comprobar que funcionase también desde Internet pasando por CloudFront:
curl -sS \
-H 'Accept-Encoding: gzip' \
-D - \
-o /dev/null \
-w 'download=%{size_download} bytes\nttfb=%{time_starttransfer}s\ntotal=%{time_total}s\n' \
'https://www.rubenortiz.es/?gzip-test=4'Primera petición:
content-encoding: gzip
vary: Accept-Encoding
x-cache: Miss from cloudfront
download=21769 bytesSegunda petición:
content-encoding: gzip
vary: Accept-Encoding
x-cache: Hit from cloudfront
age: 8
download=21769 bytes
ttfb=0.797534s
total=0.798718sLa cadena completa ya estaba funcionando:
Browser
│
│ Accept-Encoding: gzip
▼
CloudFront
│
▼
Nginx
│
│ gzip
▼
WordPress
D
7. Diferir JQuery
Uno de los recursos que Lighthouse marcaba como bloqueante era jquery.min.js, con unos 31 KB y cerca de 920 ms dentro de la ruta crítica de renderizado. El problema no era tanto el peso del archivo como el hecho de que el navegador debía descargarlo y procesarlo antes de continuar con el render inicial de la página, pudiendo retrasar métricas como FCP y LCP.
En Autoptimize ya tenía activada la opción “Do not aggregate but defer”, que permite cargar los scripts individuales con el atributo defer, pero jQuery estaba excluido explícitamente mediante js/jquery/jquery.min.js. Tras eliminar únicamente esa exclusión y vaciar la caché de Autoptimize, tanto jquery-core como jquery-migratecomenzaron a servirse con defer, manteniendo intacta la funcionalidad del sitio. La siguiente ejecución de Lighthouse confirmó que jQuery había desaparecido completamente de la sección Render-blocking requests, quedando únicamente el CSS generado por Autoptimize.
El ahorro global estimado de recursos bloqueantes pasó de aproximadamente 1.110 ms a 980 ms.
Las métricas también mejoraron ligeramente
FCP de 1,7 s a 1,5 s,
LCP de 3,6 s a 3,4 s y
Speed Index de 3,5 s a 3,3 s
aunque una variación tan pequeña puede entrar dentro de la dispersión normal entre ejecuciones de Lighthouse. Lo importante en este caso es que se eliminó correctamente un recurso JavaScript de la ruta crítica sin romper dependencias ni introducir errores en la web.
8. Ampliar la caché a un año
Además de reducir el peso de los recursos, revisé la política de caché de los archivos generados por Autoptimize.
Wakari detectaba que el CSS principal, por ejemplo autoptimize_b7e1ec6b8133370482e43a1431d3a757.css, tenía una caché de solo 30 días (max-age=2592000). Como estos archivos incluyen un hash en el nombre y cambian de URL cuando cambia su contenido, pueden cachearse durante mucho más tiempo sin riesgo.
Añadí una regla específica en Nginx para /wp-content/cache/autoptimize/ con expires 1y, dejando intacta la política general de 30 días para el resto de estáticos.
Tras recargar Nginx, el mismo recurso pasó a devolver Cache-Control: max-age=31536000 y una fecha de expiración a un año vista, eliminando así la advertencia de caché corta y mejorando las visitas recurrentes al evitar descargas innecesarias.
9. Cambiando font-display: block por swap
Uno de los puntos detectados por Lighthouse estaba relacionado con la fuente de iconos de Flatsome (fl-icons), que se declaraba con font-display: block. Este comportamiento puede retrasar la visualización del contenido que depende de esa fuente mientras el navegador espera a que termine de cargarse.
Para corregirlo, añadí una pequeña personalización en el tema hijo de WordPress que modifica dinámicamente esa declaración y la cambia a font-display: swap, permitiendo que el navegador muestre el contenido inmediatamente y sustituya la fuente cuando esté disponible, sin modificar directamente el tema padre.
Tras desplegar el cambio en producción, el LCP mejoró de 3,4 s a 2,5 s, una reducción de aproximadamente 0,9 segundos (~26%), mientras que el FCP se mantuvo en 1,5 s, el TBT en 0 ms y el CLS en 0,007. El Speed Index pasó de 3,3 s a 3,5 s, una variación pequeña que puede entrar dentro de la dispersión normal entre ejecuciones de Lighthouse.
Aunque una única medición no permite atribuir toda la mejora exclusivamente a este cambio, el resultado fue especialmente positivo porque se redujo de forma notable el LCP sin introducir bloqueos de JavaScript ni inestabilidad visual.
10. Resultado
Las principales mejoras obtenidas fueron:
| Recurso | Antes | Después |
|---|---|---|
| Imagen de fondo | ~395 KB JPG | 187 KB WebP |
| HTML home | ~108 KB | ~22 KB gzip |
| CSS Autoptimize | ~272 KB | ~46 KB gzip |
Especialmente significativa es la reducción del HTML:
108015 bytes
↓
21788 bytes
Aproximadamente un 80 % menos de datos transferidos.
En el caso del CSS:
271802 bytes
↓
45685 bytes
la reducción es de aproximadamente un 83 %.
Una nota sobre el TTFB
Durante las pruebas apareció una petición con un TTFB de más de 6 segundos. Antes de concluir que había un problema grave en el origin, repetí varias peticiones forzando distintos cache misses:
MISS 1 TTFB=1.648s
MISS 2 TTFB=0.831s
MISS 3 TTFB=0.858s
MISS 4 TTFB=0.674s
MISS 5 TTFB=0.739s
El valor de 6 segundos era por tanto un outlier, no el comportamiento habitual del servidor.
Después de invalidar CloudFront, una petición normal a la home devolvió:
content-encoding: gzip
x-cache: Miss from cloudfront
download=21788 bytes
ttfb=0.908004s
total=0.984070sIncluso en un cache miss, la respuesta completa quedaba por debajo de un segundo en esa prueba.
Conclusión y valores finales
El objetivo inicial era mejorar un LCP de 7,7 segundos, pero antes de buscar optimizaciones complejas había bastante margen en la propia transferencia de recursos.
Tras el cambio, una nueva ejecución de Lighthouse redujo el LCP de 3,4 s a 2,5 s. Al tratarse de una métrica sensible a las condiciones de cada ejecución, será necesario observar varias mediciones y los datos reales de usuarios para confirmar que la mejora se mantiene.
Dos cambios relativamente sencillos han reducido considerablemente el volumen inicial:
Imagen pesada → WebP
HTML/CSS/JS → gzip
Y durante el proceso apareció además un detalle fácil de pasar por alto: tener gzip on en Nginx no significa necesariamente que todas las conexiones lo estén utilizando. En mi caso estaba dentro del server de puerto 80 mientras el tráfico real llegaba por el server HTTPS de puerto 443.
Mover la configuración al contexto global solucionó el problema.
El siguiente paso será volver a medir el LCP con caché fría. Ahora que imágenes, HTML y recursos estáticos tienen un peso mucho menor, toca localizar cuál es el siguiente elemento que limita el renderizado inicial.
En la última revisión de Wakaris se aprecia mucho la mejora en rendimiento:

| Especialidad | Antes | Después | Cambio |
|---|---|---|---|
| Accesibilidad | 78% | 94% | +16 pp |
| Experiencia | 100% | 100% | = |
| Inteligencia artificial | 50% | 100% | +50 pp |
| Legal | 33% | 86% | +53 pp |
| Marketing | 80% | 67% | -13 pp |
| Posicionamiento | 78% | 89% | +11 pp |
| Presencia | 33% | 100% | +67 pp |
| Rendimiento | 33% | 83% | +50 pp |
| Seguridad | 63% | 82% | +19 pp |
Es decir según Wakaris, pasé de un 33% de rendimiento a un 83%.
En PageSpeed obtengo un 99% en versión web


Y la parte móvil también está bastante optimizada:

Links
- https://wordpress.com/support/site-speed/
- https://www.wakaris.com
- https://gtmetrix.com
- https://pagespeed.web.dev
- https://www.rubenortiz.es/implementar-wordpress-en-aws/
¿Te ha ayudado este artículo?
☕ Invítame a un café