Poner en verde los Core Web Vitals de una aplicación real
Fuente en texto plano, para humanos con prisa y para máquinas en general.
Cada auditoría de rendimiento produce el mismo documento: cuarenta hallazgos, sin orden, y una nota de que una reescritura ayudaría. Eso no le sirve a un equipo con una hoja de ruta. Lo que sigue es el orden en el que trabajamos, más o menos de mayor a menor impacto por unidad de riesgo.
Largest Contentful Paint: ¿a qué está esperando el navegador?
El LCP mide cuándo termina de renderizarse lo más grande del viewport. Casi nunca es lento porque el servidor es lento. Es lento porque el navegador no pudo empezar a trabajar en lo importante lo bastante pronto.
Primero las peticiones que bloquean el render. Cada hoja de estilo y cada script síncrono en el head tiene que descargarse, parsearse y ejecutarse antes de que se pinte nada. Cuéntalos en tu página más lenta. Incluye en línea lo que el primer viewport necesita de verdad, difiere el resto, y sospecha de cualquier build completo de un framework CSS que llega a una página que usa el 5% de él.
Las fuentes, que son el culpable único más habitual. Una fuente web descubierta dentro de un archivo CSS está a dos idas y vueltas de profundidad antes de que el navegador sepa que existe. Aloja tú, precarga uno o dos pesos de los que de verdad usas, y pon font-display: swap para que el texto se pinte al momento en un fallback. Eso solo suele mover el LCP varios cientos de milisegundos.
Luego la imagen del hero. Dimensiones correctas en vez de un original de 3000px escalado, un formato moderno, fetchpriority="high" en la única imagen que es el elemento LCP, y carga diferida en todo lo que está debajo del pliegue pero explícitamente no en esa. Cargar el hero de forma diferida es una herida autoinfligida, y una sorprendentemente frecuente.
Interaction to Next Paint: deja de bloquear el hilo principal
El INP mide el retraso entre que el usuario interactúa y que la pantalla se actualiza. La causa es casi siempre JavaScript ocupando el hilo principal cuando llega el toque.
Empieza auditando lo que publicas. Las etiquetas de terceros (analítica, gestores de etiquetas, widgets de chat, grabación de sesión) suelen ser los mayores contribuyentes y los más fáciles de diferir, poner detrás de consentimiento, o quitar del todo. Cada una es una negociación entre un requisito de marketing y un coste medible, y el coste ahora se puede medir, lo cual ayuda.
En tu propio código, busca tareas largas en un perfil y pártalas. Cede al navegador entre trozos de trabajo. Mueve el cálculo de verdad pesado a un worker. Evita el layout thrashing: leer una propiedad de geometría después de escribir otra fuerza un reflow síncrono, y hacerlo en un bucle es cómo un manejador de scroll se convierte en un tartamudeo.
Cumulative Layout Shift: reserva el espacio
El CLS es el más arreglable de los tres, porque la causa es siempre la misma: algo llegó después del layout y empujó el contenido.
Pon width y height en cada imagen y vídeo, para que el navegador reserve la caja antes de que lleguen los bytes. Dale a anuncios, embeds e iframes un contenedor fijo. No insertes nunca un banner encima del contenido existente después de la carga. Ponlo en el markup desde el principio, o superpónlo. Usa font-display: optional o un fallback con métricas emparejadas si el intercambio de fuentes desplaza de forma visible tus encabezados.
Cómo se vio esto en este sitio
Este sitio saca 100 en la home, en un stack elegido en parte para que eso sea alcanzable. En concreto: fuentes autoalojadas y precargadas; ningún script de terceros, lo que también significa ningún banner de cookies; los paneles de UI de maqueta son HTML y CSS en vez de imágenes, así que no cuestan nada de descargar y se mantienen nítidos; y las páginas de marketing publican unos 19 KB de JavaScript gzip porque cargan solo Alpine, con el framework de componentes reservado para la única página que tiene un formulario.
Esa última decisión es la que merece generalizarse. La mayoría de las páginas de la mayoría de los sitios no necesitan el JavaScript que cargan. Decidir por página y no por sitio es una preocupación de tiempo de build con un retorno real.
El orden, condensado
- Quita o difiere CSS y JavaScript que bloquean el render.
- Aloja y precarga las fuentes;
font-display: swap. - Dimensiona, formatea y prioriza bien la imagen LCP.
- Difiere, pon detrás de un gate o elimina los scripts de terceros.
- Pon dimensiones explícitas en todos los medios y embeds.
- Perfila las tareas largas y pártalas.
- Mide datos de campo, no solo puntuaciones de laboratorio.
Los pasos uno a cinco suelen ser unos días en un código existente y suelen bastar. El paso seis es donde vive el trabajo que queda, y el paso siete es el que te dice si algo de eso llegó a tus usuarios reales.
Preguntas que también surgen
¿Los Core Web Vitals afectan de verdad al ranking?
Las puntuaciones de laboratorio están en verde y los datos de campo en ámbar. ¿Cuál cuenta?
¿Una aplicación de una sola página es inherentemente peor en esto?
¿Cuánto se puede mejorar sin una reescritura?
Quién escribe esto
Alexander (Sander) van Hooff
Alexander (Sander) van Hooff construye aplicaciones web desde 2015 y hoy dedica la mayor parte de su tiempo a llevar funciones de IA a productos que ya tienen usuarios. Vuewer es su estudio, dirigido desde la provincia de Alicante para clientes de toda Europa.
Trabaja con VuewerLecturas relacionadas
Laravel multilingüe: rutas traducidas bien hechas
Por qué /nl/pricing pierde frente a /nl/tarieven, cómo construir slugs traducidos en Laravel, y los errores de hreflang que te cuestan en silencio los otros idiomas.
Por qué seguimos eligiendo Laravel en 2026
Un argumento honesto a favor de un framework de diez años: qué hace Laravel mejor que las alternativas, qué hace peor, y los casos en los que elegiríamos otra cosa.
SEO, AEO y GEO: qué ha cambiado de verdad
Tres siglas, un cambio: los buscadores ahora responden en vez de enlazar. Qué cambia eso sobre cómo hay que escribir las páginas, y qué no cambia en absoluto.