Guía de Core Web Vitals para la priorización de recursos
No dejes que el navegador adivine. ¡Oblígalo a cargar lo importante cuando importa!
Guía de Core Web Vitals para la priorización de recursos
El motor de priorización predeterminado del navegador opera con heurísticas (conjeturas imperfectas basadas en tipos de archivo y ubicación en el documento). Los recursos se ponen en cola en función de cuándo son descubiertos por el escáner de precarga o el parser del DOM.

Esto puede convertirse en un problema cuando consideras que el ancho de banda de red y la CPU no son recursos ilimitados. Por ejemplo: cada byte transferido para un script de seguimiento de baja prioridad, mientras se descarga al mismo tiempo, compite directamente con los bytes necesarios para tu Largest Contentful Paint (LCP).
Esto no es culpa del navegador: en el HTML de nuestro ejemplo, el navegador no tenía forma de saber que había priorizado los recursos incorrectos, lo que retrasó el renderizado crítico.
Tú eres quien sabe qué es importante y controlas esta programación a través de dos mecanismos: Priorización (impulsar señales críticas) y De-priorización (programar recursos no críticos para cuando sean menos intrusivos).
Table of Contents!
Limitaciones de las heurísticas del navegador
Los navegadores asignan prioridad basándose en una puntuación de "prioridad calculada". Esta puntuación se deriva del tipo de recurso (CSS, Script, Imagen) y su posición en el HTML/DOM. Aunque generalmente es efectivo para documentos simples, este sistema falla cuando los recursos no son reconocidos tempranamente (por el escáner de precarga) o cuando se activan los recursos incorrectos para una descarga temprana.
La limitación del escáner de precarga
Para acelerar el descubrimiento, los navegadores emplean un "escáner de precarga", un parser ligero que se adelanta al parser HTML principal para encontrar URLs de recursos. Este escáner tiene limitaciones (que lo hacen rápido y efectivo): solo analiza HTML. No puede ver dentro de archivos CSS, no ejecuta JavaScript y no renderiza (por lo que no puede 'ver si los recursos son visibles en el viewport').
Como consecuencia, cualquier recurso referenciado en una hoja de estilos (como una imagen de fondo o una fuente web), inyectado por un script o cargado de forma diferida, es omitido o ni siquiera visto hasta que el parser principal descarga y procesa toda la página web. Esto crea un "retraso de descubrimiento", donde el navegador efectivamente desconoce que existen recursos críticos.
Contención de recursos
Cuando el navegador descubre recursos, a menudo intenta descargarlos simultáneamente con otras solicitudes pendientes. Si una imagen LCP importante compite con un script de prioridad media o imágenes sin importancia (como iconos de redes sociales en el pie de página), dividen el ancho de banda disponible. Esta contención extiende el tiempo de carga para ambos, empujando la métrica LCP a la zona de "Necesita mejoras".
Estrategias de priorización manual
Para construir una ruta de renderizado rápida, debes intervenir manualmente. El objetivo es maximizar el ancho de banda para el LCP y minimizarlo para todo lo demás.
1. Corregir el descubrimiento con precarga
Debes exponer manualmente los recursos ocultos al escáner de precarga. Al mover los recursos críticos al <head> del HTML usando rel="preload", obligas al navegador a reconocerlos inmediatamente, eliminando el retraso de descubrimiento.
La implementación:
<!-- Exponer la fuente al escáner inmediatamente --> <link rel="preload" as="font" type="font/woff2" href="/fonts/inter-bold.woff2" crossorigin> <!-- Exponer la imagen LCP de fondo inmediatamente --> <link rel="preload" as="image" href="/images/hero-banner.jpg" fetchpriority="high">
2. Anular las heurísticas del LCP
Los navegadores a menudo asignan prioridad "Baja" o "Media" a las imágenes porque no conocen las dimensiones finales del diseño durante la obtención inicial. El navegador no puede determinar si una imagen es el LCP hasta después de que se construye el árbol de renderizado, lo cual es demasiado tarde.
La implementación:
Fuerza el estado de prioridad "Alta" en el elemento LCP usando fetchpriority="high". Esto omite las heurísticas internas y coloca la imagen al frente de la cola de descarga.
<!-- Forzar obtención inmediata de alta prioridad --> <img src="hero.jpg" alt="Hero Product" fetchpriority="high">
3. De-priorizar imágenes sin importancia
Liberar ancho de banda es a menudo más efectivo que aumentar la prioridad. Debes retrasar explícitamente los recursos no esenciales para liberar la tubería de red para los recursos críticos.
La implementación:
- Debajo del pliegue: Usa loading="lazy" para diferir la descarga hasta que el usuario haga scroll.
- Encima del pliegue secundario: Usa fetchpriority="low" para diapositivas de carrusel o elementos visuales secundarios que se renderizan inicialmente pero son menos importantes que el LCP.
- Encima del pliegue y visualmente sin importancia: Omite el escáner de precarga usando loading="lazy" y asigna un ancho de banda bajo. Útil para esas imágenes pequeñas como banderas o iconos que nunca llaman la atención durante un primer renderizado pero que podrían generar muchas solicitudes de ancho de banda temprano.
<!-- Imagen LCP: Máxima prioridad --> <img src="slide-1.jpg" fetchpriority="high"> <!-- Imagen secundaria del carrusel: Obtención inmediata, bajo uso de ancho de banda --> <img src="slide-2.jpg" fetchpriority="low"> <!-- Banderas de traducción: aunque estén en el viewport, ocultarlas del escáner de precarga --> <img src="dutch-flag.jpg" loading="lazy" fetchpriority="low"> <!-- Imagen fuera de pantalla: Obtención diferida --> <img src="footer-promo.jpg" loading="lazy">
4. Controlar la ejecución de scripts
JavaScript bloquea el parser del DOM. Si usas etiquetas <script> estándar, el navegador detiene el análisis del HTML para descargar y ejecutar el archivo.
La implementación:
- defer: Úsalo para la lógica de la aplicación. Se descarga en paralelo (baja prioridad) y se ejecuta solo después de que el HTML se ha analizado completamente, preservando el orden de dependencias.
- async: Úsalo para scripts independientes de terceros (como analytics). Se descarga en paralelo y se ejecuta inmediatamente al completarse, sin respetar el orden.
- Inyectar: Omite el escáner de precarga para que no compita con el ancho de banda temprano. Los scripts inyectados se tratan como async.
- Programar + Inyectar: Inyectar scripts en un momento posterior, por ejemplo cuando el evento load se ha disparado.
<!-- Lógica de la aplicación: No bloqueante, preserva el orden de ejecución -->
<script src="app.js" defer></script>
<!-- Consentimiento de terceros: No bloqueante, ejecución independiente -->
<script src="consent.js" async></script>
<script>
/* Ejemplo de inyección de analytics */
const script = document.createElement('script');
script.src = 'analytics.js';
script.async = true;
document.head.appendChild(script);
/* Ejemplo de inyectar + programar para chat */
window.addEventListener('load', () => {
const chatScript = document.createElement('script');
chatScript.src = 'chat-widget.js';
document.head.appendChild(chatScript);
});
</script>5. Desbloquear el renderizado de CSS
CSS bloquea el renderizado por diseño: el navegador no sabe cómo se ve la página sin CSS. Por lo tanto, descarga y analiza las hojas de estilo primero.
Estrategias de optimización:
- Evitar @import: Crea cadenas de dependencia secuenciales que devastan el rendimiento.
- Optimizar el tamaño del paquete: Evita archivos CSS menores de 3kB (sobrecarga) y mayores de 20kB (bloqueo). Idealmente, apunta a archivos de ~15kB.
- Carga asíncrona: Carga los estilos fuera de pantalla de forma asíncrona para desbloquear la ruta crítica.
- Compensación de CSS crítico: Aunque incluir CSS crítico en línea mejora la primera vista de página, omite la caché del navegador, lo que puede retrasar las vistas de página posteriores.
La implementación:
Elimina @import por completo. Usa etiquetas <link> para carga en paralelo. Para CSS no crítico (como estilos de impresión), usa el atributo media para desbloquear el hilo principal.
<!-- CSS crítico: Bloquea el renderizado (Correcto) --> <link rel="stylesheet" href="main.css"> <!-- CSS de impresión: No bloqueante hasta que ocurra el evento de impresión --> <link rel="stylesheet" href="print.css" media="print"> <!-- Patrón asíncrono: Carga con baja prioridad, se aplica al cargar --> <link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
6. Estabilizar el renderizado de fuentes
Las fuentes son recursos pesados y bloqueantes. La priorización efectiva requiere límites estrictos en lo que se descarga y control sobre cómo se renderiza.
Estrategias de optimización:
- Límites estrictos de precarga: Precarga solo los 1-2 archivos de fuentes más importantes (generalmente el texto del LCP). Precargar más de 5 fuentes congestiona el ancho de banda.
- Reducir el payload: Usa fuentes variables (un archivo para todos los pesos) y subsetting (eliminar caracteres no utilizados) para minimizar el tamaño del archivo.
- Estrategia de renderizado:
- Usa
swappara renderizado rápido (evita FOIT/texto invisible). - Usa
optionalpara prevenir CLS (evita cambios de diseño en redes lentas).
- Usa
La implementación:
<!-- Precargar SOLO el subconjunto crítico (ej. Encabezado + Cuerpo) -->
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
font-family: 'Inter Variable';
src: url('/fonts/inter-var.woff2') format('woff2-variations');
/* Elige según los requisitos de estabilidad: */
font-display: optional; /* Sin cambio de diseño, pero la fuente podría quedarse como fallback */
/* font-display: swap; Visibilidad de texto más rápida, pero riesgo de cambio de diseño */
}
</style>
Your dev team is busy.
Delegate the performance architecture to a specialist. I handle the optimization track while your team ships the product.
- Parallel Workflows
- Specialized Expertise
- Faster Delivery