Nota revisada y reescrita el 18 de octubre de 2026: la versión original tenía errores y datos sin fuente.
El Largest Contentful Paint (LCP) mide cuánto tarda en pintarse el elemento más grande visible al cargar: normalmente la imagen principal o un titular. Se considera bueno por debajo de 2,5 segundos en el percentil 75 de las visitas reales. Antes de tocar nada, hay que saber qué elemento es y en qué fase se va el tiempo.
1. Encontrar el elemento LCP
En Chrome DevTools, pestaña Performance, graba una carga con throttling de red y CPU de móvil. La pista Timings marca el LCP y, al seleccionarlo, te dice qué nodo es. Desde código:
new PerformanceObserver((list) => {
const entries = list.getEntries();
const last = entries[entries.length - 1];
console.log('LCP', Math.round(last.startTime), last.element);
}).observe({ type: 'largest-contentful-paint', buffered: true });
2. Las cuatro fases
El LCP de una imagen se divide en:
- TTFB: hasta que llega el primer byte del HTML.
- Retraso de carga del recurso: desde el TTFB hasta que el navegador empieza a pedir la imagen.
- Duración de la carga: lo que tarda en descargarse.
- Retraso de renderizado: desde que se descarga hasta que se pinta.
La guía de web.dev pone como referencia que casi todo el tiempo se vaya en TTFB y descarga, y que las dos fases de "retraso" sean mínimas. El error típico en Next.js está en la fase 2: la imagen principal se descubre tarde o se carga en modo lazy.
3. La imagen principal con next/image
next/image carga con loading="lazy" por defecto. Para la imagen que es el LCP eso es justo lo contrario de lo que quieres. Márcala como prioritaria:
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Producto destacado"
width={1200}
height={630}
sizes="100vw"
fetchPriority="high"
loading="eager"
/>
);
}
- Next.js 16: la prop
priorityestá obsoleta. La documentación recomiendaloading="eager"ofetchPriority="high", y reservarpreloadpara cuando necesitas que la petición salga desde el<head>. - Next.js 13 a 15:
priorityhace eso mismo (precarga y quita el lazy). En estas versiones es la forma estándar. - Solo una o dos imágenes. Si marcas como prioritarias diez, compiten entre ellas y no ganas nada.
sizescorrecto. Sinsizes, una imagen que en móvil ocupa media pantalla puede descargarse al ancho del escritorio. Ese peso de más se nota en la fase 3.
4. Cuando el LCP es texto
Si el elemento LCP es un titular, lo que lo retrasa suele ser la fuente web. next/font descarga la fuente en el build, la sirve desde tu dominio y aplica font-display: swap por defecto, así que el texto se pinta con una fuente de respaldo mientras llega la definitiva:
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
5. Otros retrasos de renderizado
- Imagen de fondo en CSS (
background-image): el navegador no la descubre hasta tener el CSS aplicado. Si es el LCP, conviértela en un<Image>o precárgala. - Contenido que se pinta en el cliente: si el hero depende de un
useEffecto de datos que se piden desde el navegador, el LCP espera a JavaScript. Renderízalo en el servidor. - Animaciones de entrada que empiezan con
opacity: 0: el elemento no cuenta como pintado hasta que se ve.
6. Medir con datos reales
Lighthouse simula una carga. El dato que importa es el de usuarios reales: el informe de Core Web Vitals de Search Console, PageSpeed Insights (la sección de CrUX) o tu propia medición de campo con web-vitals. Un cambio que mejora Lighthouse y no mueve el p75 real no ha resuelto el problema.