Ver contenido
Guía de CSS Crítico: Extrae, Inserta en Línea y Difiere Estilos
Introducción
El CSS crítico es el subconjunto mínimo de estilos necesarios para renderizar el contenido visible en la primera pantalla ("above the fold") sin esperar a que se descargue toda la hoja de estilos del sitio. Chrome recomienda explícitamente "extraer CSS crítico" y "diferir CSS no crítico" como parte de su auditoría para minimizar el trabajo del hilo principal. Esta guía cubre cómo implementarlo paso a paso. El UXR SEO Analyzer señala cuando detecta hojas de estilo completas bloqueando el renderizado en lugar de CSS crítico insertado en línea.
Por Qué Importa el CSS Crítico
Por defecto, el navegador no puede construir el árbol de renderizado hasta procesar todo el CSS que encuentra en el <head>—esto es parte de la ruta crítica de renderizado. Si tu hoja de estilos principal pesa 200 KB pero solo 8 KB corresponden a lo que el usuario ve antes de hacer scroll, el navegador sigue esperando los 200 KB completos antes de pintar nada. Insertar en línea solo esos 8 KB y diferir el resto elimina ese bloqueo.
Esto conecta directamente con el desglose técnico de LCP: cuando el elemento LCP es un bloque de texto o depende del layout inicial, un retraso de renderizado alto suele deberse a CSS bloqueante, no a una imagen lenta. Reducir esa fase es exactamente lo que logra un CSS crítico bien implementado.
Paso 1: Identifica el CSS Crítico
El CSS crítico corresponde a los estilos que afectan elementos visibles en el viewport inicial, en los tamaños de pantalla que te importan (móvil y escritorio, dado el breakpoint único de tu proyecto). Herramientas automatizadas como critical, penthouse o beasties (el sucesor mantenido de Critters) renderizan la página en un navegador headless y extraen las reglas CSS que realmente se aplican a ese viewport.
// build-critical-css.js — ejemplo con el paquete "critical"
const critical = require('critical');
await critical.generate({
inline: true,
base: 'dist/',
src: 'index.html',
target: 'index.html',
width: 1300,
height: 900,
dimensions: [
{ width: 375, height: 812 }, // móvil
{ width: 1300, height: 900 }, // escritorio
],
});
Paso 2: Inserta el CSS Crítico en Línea
El resultado se inyecta directamente en un <style> dentro del <head>, evitando una solicitud de red adicional para el primer pintado:
<head>
<style>
/* CSS crítico generado, solo ~8KB */
body { margin: 0; font-family: system-ui, sans-serif; }
.hero { min-height: 480px; background: #f5f5f5; }
.hero h1 { font-size: 2.5rem; }
</style>
</head>
Paso 3: Difiere el CSS No Crítico
El resto de la hoja de estilos debe cargarse sin bloquear el renderizado. El patrón estándar usa rel="preload" con un cambio de rel al terminar de cargar, con un <noscript> de respaldo:
<link rel="preload" href="/styles/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/main.css"></noscript>
Este patrón descarga main.css con prioridad baja (no bloqueante) y lo activa como hoja de estilos real una vez descargado, sin retrasar el primer pintado.
Herramientas por Stack
| Stack | Enfoque recomendado |
|---|---|
| Sitios estáticos / SSG | Extraer CSS crítico en tiempo de build con critical o beasties, por página |
| Vite / React / Vue | Plugin de build que ejecuta la extracción sobre el HTML generado antes de desplegar |
| Next.js | CSS-in-JS con extracción crítica automática, o un paso de post-build equivalente |
| WordPress y CMS tradicionales | Plugins de rendimiento que generan CSS crítico por plantilla |
Automatiza la Extracción en tu Pipeline de Build
El CSS crítico se vuelve obsoleto cada vez que cambias el layout, así que generarlo manualmente no escala. La forma correcta es integrarlo como un paso del build que se ejecuta en cada despliegue:
- El build genera el HTML y CSS finales como de costumbre
- Un script post-build (usando
critical,beastieso equivalente) abre cada página generada en un navegador headless - El script extrae las reglas CSS aplicadas al viewport definido y las inserta en línea en el
<head>de cada archivo HTML - El CI falla si el paso de extracción produce un bloque superior al presupuesto de tamaño definido (por ejemplo, 14KB)
Para sitios SSG con cientos de páginas, este paso puede paralelizarse por página sin afectar el tiempo de build de forma significativa, ya que cada extracción es independiente.
CSS Crítico y Estabilidad Visual (CLS)
Un efecto secundario importante: si el CSS crítico omite las dimensiones de un elemento por encima del pliegue (por ejemplo, un contenedor de imagen sin aspect-ratio ni min-height), el navegador puede pintar ese elemento con dimensiones incorrectas y luego corregirlas cuando llega el CSS completo—produciendo exactamente el tipo de layout shift que CLS penaliza. Al construir el CSS crítico, verifica que incluya cualquier regla que reserve espacio (dimensiones, aspect-ratio, min-height) para elementos visibles arriba del pliegue, no solo el color y la tipografía.
Errores Comunes
- Extraer demasiado CSS "crítico"—si el bloque insertado en línea supera ~14KB, empieza a competir con el propio HTML por el primer paquete TCP y pierde parte de su ventaja
- Generar el CSS crítico para un solo viewport, ignorando el layout móvil que verá la mayoría de tus usuarios
- Olvidar regenerar el CSS crítico después de cambios de diseño, dejando estilos obsoletos insertados en línea
- Diferir estilos que sí son críticos, causando un "flash" visible de contenido sin estilo (FOUC) al aplicarse la hoja completa
Relación con Otras Guías de este Hub
El CSS crítico es solo uno de los recursos que puede bloquear el renderizado. Si después de implementarlo Lighthouse sigue reportando recursos bloqueantes, es probable que el problema esté en scripts síncronos en el <head>—cubierto en Recursos que Bloquean el Renderizado Explicado—o en un TTFB lento que retrasa la llegada del HTML antes de que cualquier CSS, crítico o no, pueda aplicarse.
Checklist de CSS Crítico
- [ ] CSS crítico extraído por plantilla o tipo de página, no un único bloque genérico
- [ ] Bloque insertado en línea por debajo de ~14KB comprimido
- [ ] Dimensiones y
aspect-ratiode elementos above-the-fold incluidas en el bloque crítico - [ ] Hoja de estilos completa cargada con
rel="preload"+ cambio astylesheet, con fallback<noscript> - [ ] Extracción automatizada como paso de build, no un proceso manual
- [ ] Verificado en Lighthouse que la hoja completa ya no aparece como recurso bloqueante
Cómo Verificarlo
Después de implementar CSS crítico, confirma en el panel Network de Chrome DevTools que la hoja de estilos principal se descarga con prioridad baja y no aparece en la lista de "render-blocking resources" de Lighthouse. El UXR SEO Analyzer también marca esto en su pestaña de Performance.
Preguntas Frecuentes
¿Cuánto CSS crítico es demasiado?
Como regla práctica, mantén el bloque insertado en línea por debajo de 14KB comprimido—el tamaño de la ventana de congestión TCP inicial en la mayoría de conexiones. Más que eso empieza a retrasar el HTML en lugar de acelerarlo.
¿Necesito CSS crítico distinto por página?
En sitios con plantillas muy diferentes (home, producto, artículo), sí—cada plantilla tiene su propio "above the fold". En sitios con un layout compartido, un solo bloque crítico para el shell (header, navegación) suele bastar.
¿El CSS crítico reemplaza minificar y comprimir el CSS normal?
No. Son complementarios: minifica y comprime toda tu hoja de estilos como práctica base, y además extrae el subconjunto crítico para el primer pintado.
¿Qué pasa si uso CSS-in-JS en lugar de hojas de estilo separadas?
El principio es el mismo, pero la extracción cambia: en lugar de analizar un archivo .css, la librería CSS-in-JS necesita soporte nativo para extracción crítica en el servidor (renderizar la página y recolectar solo las clases usadas). Varias librerías modernas de CSS-in-JS incluyen esta capacidad; verifica la documentación de la tuya antes de intentar extraerlo manualmente.
Guías Relacionadas
Referencias
- Chrome Developers - Minimize main thread work
- Chrome Developers - Eliminate render-blocking resources
- Chrome Developers - Avoid chaining critical requests
- web.dev - Core Web Vitals
