Optimización de Core Web Vitals
Optimización dirigida para los tres Core Web Vitals usando datos de campo para identificar el impacto en usuarios y trazas del navegador para diagnosticar causas.
Mide antes de optimizar
Cuando una URL ejecutable esté disponible, consulta el flujo de trabajo de medición de rendimiento. Prefiere esta secuencia:
- Revisa los datos p75 de CrUX a nivel de página, con una referencia de origen claramente etiquetada cuando los datos de página no estén disponibles.
- Graba una traza de rendimiento del navegador bajo las condiciones indicadas. Con Chrome DevTools MCP, los resúmenes de traza pueden incluir CrUX junto con las métricas de laboratorio observadas.
- Analiza solo las perspectivas asociadas con la métrica fallida, luego inspecciona el código y los recursos implicados.
- Vuelve a ejecutar mediciones de laboratorio equivalentes después de la corrección. No afirmes una mejora inmediata de campo; CrUX y RUM de origen propio necesitan nuevas visitas de usuarios.
Si solo está disponible el código fuente, identifica las causas probables pero no afirmes que LCP, INP o CLS están fallando sin evidencia de ejecución.
Las tres métricas
| Métrica | Mide | Bueno | Necesita mejora | Pobre |
|---|---|---|---|---|
| LCP | Carga | ≤ 2.5s | 2.5s – 4s | > 4s |
| INP | Interactividad | ≤ 200ms | 200ms – 500ms | > 500ms |
| CLS | Estabilidad Visual | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |
Google mide en el percentil 75: el 75% de las visitas a la página deben cumplir con los umbrales "Buenos".
LCP: Largest Contentful Paint
LCP mide cuándo se renderiza el elemento de contenido visible más grande. Generalmente es:
- Imagen principal o video
- Bloque de texto grande
- Imagen de fondo
- Elemento
<svg>
Problemas comunes de LCP
1. Respuesta lenta del servidor (TTFB > 800ms)
Solución: CDN, almacenamiento en caché, backend optimizado, renderizado en el borde
2. Recursos que bloquean el renderizado
<!-- ❌ Bloquea el renderizado -->
<link rel="stylesheet" href="/all-styles.css">
<!-- ✅ CSS crítico en línea, el resto diferido -->
<style>/* CSS crítico para la parte visible */</style>
<link rel="preload" href="/styles.css" as="style"
onload="this.onload=null;this.rel='stylesheet'">
3. Tiempos de carga lentos de recursos
<!-- ❌ La imagen LCP se descubre solo después de cargar una hoja de estilo -->
<div class="hero"></div>
<!-- ✅ Detectable en el HTML inicial y priorizada -->
<link rel="preload" href="/hero.webp" as="image" fetchpriority="high">
<img src="/hero.webp" alt="Hero" fetchpriority="high">
Prefiere un <img> detectable con fetchpriority="high". Añade la precarga solo cuando la traza muestre que el recurso se descubriría tarde; las precargas duplicadas o especulativas pueden competir por el ancho de banda.
4. Retrasos por renderizado del lado del cliente
// ❌ El contenido se carga después de JavaScript
useEffect(() => {
fetch('/api/hero-text').then(r => r.json()).then(setHeroText);
}, []);
// ✅ Renderizado del lado del servidor o estático
// Usa SSR, SSG o streaming para enviar HTML con contenido
export async function getServerSideProps() {
const heroText = await fetchHeroText();
return { props: { heroText } };
}
5. Haz las navegaciones instantáneas con la API de Reglas de Especulación
Para sitios con recorridos predecibles del mismo origen, prerenderizar una página siguiente probable puede hacer que una navegación posterior exitosa sea mucho más rápida. Trata esto como una optimización de navegación medida, no como un sustituto para arreglar el LCP de la página actual.
<script type="speculationrules">
{
"prerender": [{
"where": { "href_matches": "/*" },
"eagerness": "moderate"
}]
}
</script>
El comportamiento actual de Chrome es lo suficientemente específico para guiar la elección:
eagerness | Disparador |
|---|---|
conservative | Pulsación o toque hacia abajo |
moderate | Escritorio: 200ms de hover, o pulsación anterior; móvil: heurísticas de viewport |
eager | Chrome 143+: escritorio 10ms de hover; móvil 50ms después de que el enlace entre en el viewport |
immediate | Tan pronto como se observen las reglas |
Comienza de forma conservadora y mide la tasa de aciertos de predicción, bytes transferidos, carga del servidor y mejora en la navegación antes de expandir las reglas. Vuelve a consultar la documentación mantenida sobre eagerness de Chrome antes de codificar comportamientos sensibles al tiempo.
Advertencias:
- Costo de ancho de banda/CPU. Cada prerender equivale aproximadamente a una carga de página completa. Delimita
wherecuidadosamente (patroneshref_matches, excluye logout/checkout) y evitaimmediatefuera de sitios pequeños. - Los efectos secundarios se disparan antes. Los análisis, anuncios y cualquier código que se ejecute al cargar se dispararán cuando comience el prerender, no cuando el usuario navegue. Condiciona los efectos secundarios al evento
prerenderingchangeo adocument.prerendering. - Solo Chromium. Safari y Firefox ignoran el script: es una mejora progresiva, nunca una regresión.
Lista de verificación de optimización de LCP
- [ ] TTFB < 800ms (usa CDN, caché en el borde)
- [ ] El recurso LCP es detectable en el HTML inicial y está priorizado; precarga solo si la traza muestra descubrimiento tardío
- [ ] Imagen LCP optimizada (WebP/AVIF, tamaño correcto)
- [ ] CSS crítico en línea (< 14KB)
- [ ] Sin JavaScript que bloquee el renderizado en <head>
- [ ] Las fuentes no bloquean el renderizado del texto (font-display: swap)
- [ ] Elemento LCP en HTML inicial (no renderizado por JS)
- [ ] Reglas de Especulación añadidas para navegaciones siguientes probables (eagerness moderate)
Identificación del elemento LCP
Este fragmento diagnostica la sesión de página actual. No son datos de campo.
// Encuentra tu elemento LCP
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('Elemento LCP:', lastEntry.element);
console.log('Tiempo LCP:', lastEntry.startTime);
}).observe({ type: 'largest-contentful-paint', buffered: true });
INP: Interaction to Next Paint
INP mide la capacidad de respuesta en clics, toques y pulsaciones de teclas durante una visita. Diagnostica su retardo de entrada, tiempo de procesamiento y retardo de presentación por separado; una interacción lenta puede implicar contención del hilo principal antes del controlador, trabajo costoso de la aplicación o renderizado retrasado después.
Cuando el INP de campo es pobre o una traza identifica una interacción lenta, consulta la referencia de INP para interpretación de trazas, patrones de rendición, causas de terceros y de renderizado, un observador de sesión única y atribución de origen propio.
CLS: Cumulative Layout Shift
CLS mide cambios de diseño inesperados a lo largo de una visita a la página. Usa atribución de campo o una traza para identificar el nodo desplazado y el desencadenante; no asumas que la víctima visible causó el cambio.
Cuando el CLS de campo es pobre o una traza informa cambios, consulta la referencia de CLS para patrones de espacio reservado, contenido dinámico, correcciones de fuentes y animaciones, un observador de depuración y una lista de verificación.
Fuentes de medición
| Fuente | Uso |
|---|---|
Traza de rendimiento del navegador (Chrome DevTools MCP: performance_start_trace) | Observa una carga o interacción y diagnostica perspectivas enfocadas; usa el contexto de CrUX incluido cuando esté disponible |
| CrUX o Search Console | Prioriza resultados reales agregados de usuarios en p75 |
| Lighthouse CLI o PageSpeed Insights | Referencia de laboratorio controlada cuando las herramientas de DevTools no están disponibles |
| RUM de origen propio | Segmenta la experiencia de producción actual por ruta, dispositivo, versión y atribución |
PerformanceObserver sin formato | Inspecciona una sesión de página durante la depuración |
No enrutes el rendimiento a través de lighthouse_audit de Chrome DevTools MCP; esa capacidad cubre intencionalmente categorías de Lighthouse que no son de rendimiento. No compares un solo valor de laboratorio directamente con un p75 de campo como si fueran muestras equivalentes.
Al añadir o revisar la recopilación en producción, consulta la referencia de RUM de origen propio. Prefiere la biblioteca web-vitals porque las API sin procesar del navegador no implementan por sí mismas todas las reglas de ciclo de vida y reporte de cada Core Web Vital.
Soluciones rápidas por framework
Next.js
// LCP: Usa next/image con priority
import Image from 'next/image';
<Image src="/hero.jpg" priority fill alt="Hero" />
// INP: Usa importaciones dinámicas
const HeavyComponent = dynamic(() => import('./Heavy'), { ssr: false });
// CLS: El componente Image maneja las dimensiones automáticamente
React
// LCP: Precarga en head
<link rel="preload" href="/hero.jpg" as="image" fetchpriority="high" />
// INP: Memoiza y usa useTransition
const [isPending, startTransition] = useTransition();
startTransition(() => setExpensiveState(newValue));
// CLS: Siempre especifica dimensiones en las etiquetas img
Vue/Nuxt
<!-- LCP: Usa nuxt/image con preload -->
<NuxtImg src="/hero.jpg" preload loading="eager" />
<!-- INP: Usa componentes asíncronos -->
<component :is="() => import('./Heavy.vue')" />
<!-- CLS: Usa CSS aspect-ratio -->
<img :style="{ aspectRatio: '16/9' }" />
Referencias
- Optimización detallada de LCP — léelo cuando una traza LCP apunte a retrasos de descubrimiento, carga o renderizado
- Optimización detallada de INP — léelo cuando una traza o atribución de campo identifique una interacción lenta
- Optimización detallada de CLS — léelo cuando una traza o atribución de campo identifique cambios inesperados
- web.dev LCP
- web.dev INP
- web.dev CLS
- Habilidad de rendimiento
