# Poner en verde los Core Web Vitals de una aplicación real

> Arregla las tres métricas en orden de impacto: recorta las peticiones que bloquean el render y sirve bien la imagen del hero para el LCP, parte las tareas largas de JavaScript para el INP, y reserva espacio para todo lo que carga tarde para el CLS. En la mayoría de las aplicaciones existentes, cuatro cambios (carga de fuentes, tamaño de imágenes, scripts de terceros diferidos y dimensiones explícitas) te llevan de ámbar a verde sin tocar la arquitectura.

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

1. Quita o difiere CSS y JavaScript que bloquean el render.
2. Aloja y precarga las fuentes; `font-display: swap`.
3. Dimensiona, formatea y prioriza bien la imagen LCP.
4. Difiere, pon detrás de un gate o elimina los scripts de terceros.
5. Pon dimensiones explícitas en todos los medios y embeds.
6. Perfila las tareas largas y pártalas.
7. 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.

---

Publicado por Vuewer. Funciones de IA y aplicaciones web, llevadas a producción.
Versión canónica: https://vuewer.com/es/blog/core-web-vitals-en-una-aplicacion-real