«Que la página cargue rápido» no es un requisito: nadie puede comprobar si se cumple. Un presupuesto de rendimiento sí lo es. Web.dev lo define como un conjunto de límites sobre métricas que afectan al rendimiento: el peso total de la página, el tiempo de carga en una red móvil o el número de peticiones. La parte útil es que se puede calcular a partir de un objetivo y comprobar en cada cambio, antes de que una plantilla engorde sin que nadie lo note.
Tres tipos de límite
El artículo «Performance budgets 101» de web.dev distingue tres familias. Conviene combinarlas, porque cada una tapa los huecos de las otras.
| Tipo | Ejemplos | Ventaja | Limitación |
|---|---|---|---|
| Basado en tiempos | LCP ≤ 2,5 s; TBT ≤ 200 ms en laboratorio móvil | Refleja lo que vive el usuario | Varía entre ejecuciones; no dice qué recurso sobra |
| Basado en cantidades | ≤ 150 KB de JavaScript; ≤ 2 fuentes; ≤ 25 peticiones | Estable, fácil de comprobar y de explicar a diseño | Dos páginas del mismo peso pueden cargar muy distinto según el orden |
| Basado en reglas o puntuaciones | Puntuación de rendimiento de Lighthouse ≥ 85 | Un solo número, con diagnósticos asociados | Mezcla métricas y oscila varios puntos sin cambios reales |
Criterio práctico: fija el objetivo en tiempos (LCP, porque es la Core Web Vital ligada a la carga; umbrales en LCP, INP y CLS), tradúcelo a cantidades para el día a día y usa la puntuación sólo como alarma secundaria, siempre sobre la mediana de varias ejecuciones (por qué, en Por qué PageSpeed Insights da una puntuación distinta cada vez).
Del objetivo de LCP a los kilobytes: el cálculo
La pregunta es: si quiero un LCP de 2,5 s en una conexión móvil modesta, ¿cuántos KB pueden viajar antes de que se pinte el elemento principal? Hace falta fijar una red. Aquí se toma la misma que Lighthouse usa por defecto para móvil según su documentación de limitación: 150 ms de latencia (RTT) y 1,6 Mbps de bajada. Es un supuesto; tus usuarios pueden estar mejor o peor.
Ejemplo de cálculo
Supuestos: RTT de 150 ms; 1,6 Mbps de bajada; servidor que tarda 200 ms en generar el HTML; HTTPS con TLS 1.3 sobre HTTP/2; todo servido desde el mismo origen; elemento LCP = una imagen.
1. Ancho de banda en bytes. 1,6 Mbps = 1.600.000 bits/s ÷ 8 = 200.000 bytes/s ≈ 200 KB por segundo.
2. Tiempo que se va en esperas, no en descargas.
- DNS + conexión TCP + negociación TLS 1.3: unos 3 RTT = 3 × 150 = 450 ms.
- Petición del HTML: 1 RTT (150 ms) + 200 ms de servidor = 350 ms.
- El navegador encuentra CSS, fuente e imagen LCP al leer el HTML y las pide: al menos 1 RTT más = 150 ms (si la imagen sólo aparece referenciada en el CSS, súmale otro).
- Margen para análisis, estilos, decodificación de la imagen y pintado en un móvil de gama media: 400 ms (estimación).
Total de esperas: 450 + 350 + 150 + 400 = 1.350 ms.
3. Tiempo que queda para transferir: 2.500 − 1.350 = 1.150 ms.
4. Bytes que caben: 1,15 s × 200 KB/s = 230 KB de techo teórico.
5. Ajuste realista. TCP no arranca a plena velocidad (arranque lento) y un segundo RTT para localizar recursos es habitual, así que conviene recortar un 25 %: 230 × 0,75 ≈ 170 KB comprimidos en la ruta crítica.
No es casualidad que la cifra se parezca a la que propone «Performance budgets 101»: menos de 170 KB de recursos de ruta crítica, comprimidos y minificados, como línea base razonable. Ese artículo es de 2018 y razonaba con otras métricas, pero el orden de magnitud sigue siendo útil.
Las cuentas son una aproximación de servilleta: Lighthouse no carga la página así, sino que simula la carga con su propio modelo, y tus usuarios reales no tienen todos la misma red. Sirven para decidir órdenes de magnitud (¿caben 170 KB o 700 KB?), no para predecir el LCP con precisión de décimas. Para confirmar, mide con método, como se explica en Cómo montar un experimento web.
Reparto del presupuesto por tipo de recurso
Con unos 170 KB críticos, el siguiente paso es repartirlos. Lo que no está en la ruta crítica (imágenes bajo el pliegue con loading="lazy", JavaScript diferido, anuncios cargados de forma asíncrona) va en una segunda columna con su propio techo, porque también consume datos y CPU, aunque no retrase el LCP del mismo modo.
| Recurso | Ruta crítica | Resto de la carga | Nº máx. de peticiones | Nota |
|---|---|---|---|---|
| HTML | 20 KB | — | 1 | Comprimido con gzip o Brotli |
| CSS | 20 KB | — | 1–2 | Bloquea el renderizado: cuanto menos, mejor |
| Fuentes | 30 KB | 20 KB | 2 | WOFF2 y subconjuntos; ver tipografías web |
| JavaScript propio | 30 KB | 70 KB | 3 | Diferido salvo lo imprescindible |
| Imagen LCP | 70 KB | — | 1 | AVIF o WebP al tamaño mostrado |
| Otras imágenes | — | 300 KB | 10 | Diferidas, con width y height |
| Terceros (anuncios, analítica) | 0 KB | Ver siguiente sección | 10 | Nunca antes del LCP |
| Total | 170 KB | 390 KB + terceros | ≈ 30 |
Las cifras son un punto de partida editorial, no una norma. Una tienda con galería necesitará más imagen y menos texto; un blog estático puede quedarse muy por debajo. Lo que importa es que la suma de la columna crítica no supere lo calculado.
Qué cambia al añadir anuncios
Los scripts de anuncios son el caso típico de presupuesto que se rompe sin tocar tu código: el peso y el JavaScript que llegan dependen de la red publicitaria y de la creatividad que gane cada subasta, y cambian de una carga a otra. Tres efectos a prever:
Ancho de banda
Supón que el conjunto de scripts y creatividades suma 150 KB (cifra ilustrativa; mídela en tu caso con la pestaña Red). A 200 KB/s, si compiten con la ruta crítica, son 0,75 s más de transferencia: con el cálculo anterior, el LCP pasaría de 2,5 s a unos 3,25 s. Por eso los scripts publicitarios se cargan con async y no deben retrasar la imagen principal.
Hilo principal
El JavaScript de terceros se ejecuta en el mismo hilo que el tuyo. En laboratorio se nota en TBT, la métrica que más pesa en la puntuación de Lighthouse (30 %); en campo, en INP. Reserva parte del presupuesto de JavaScript para ellos o, al menos, un límite de peticiones de terceros.
Espacio en pantalla y CLS
Un anuncio que aparece sin espacio reservado empuja el contenido hacia abajo. La guía de web.dev para optimizar CLS recomienda reservar el espacio en el diseño inicial, con min-height o aspect-ratio, y reconoce el dilema: reservar el tamaño máximo evita el salto pero deja hueco en blanco si llega un anuncio menor; reservar el tamaño más probable deja algún salto ocasional. Con min-height, a diferencia de height, un anuncio mayor puede mostrarse entero.
Ejemplo de cálculo: CLS de un anuncio sin espacio reservado
Supón una pantalla móvil de 400 × 800 px. El texto ocupa desde y = 300 hasta el final de la pantalla, a todo el ancho. Llega un anuncio de 250 px de alto justo encima y lo empuja.
La puntuación de un desplazamiento es fracción de impacto × fracción de distancia. La zona afectada va de y = 300 a y = 800 (antes y después del salto): 500 / 800 = 0,625. El contenido se mueve 250 px: 250 / 800 = 0,3125. Puntuación: 0,625 × 0,3125 ≈ 0,20, por encima del umbral de «bueno» (0,1).
Con min-height: 250px en el contenedor, el texto ya empieza en y = 550 y no se mueve: 0. Si llega una creatividad de 280 px, el texto baja 30 px: zona afectada 550–800, es decir, 250 / 800 = 0,3125; distancia 30 / 800 = 0,0375; puntuación ≈ 0,012. Asumible.
Del papel a la configuración: budget.json y Lighthouse CI
Durante años, Lighthouse aceptó un archivo budget.json con la opción --budget-path. Su formato es un array de presupuestos; cada uno puede llevar path (a qué URLs se aplica, con sintaxis tipo robots.txt), timings (métrica y límite en milisegundos), resourceSizes (en KB) y resourceCounts. Los tipos de recurso válidos son document, font, image, media, other, script, stylesheet, third-party y total. Con el reparto anterior quedaría así:
[
{
"path": "/articulos/*",
"options": { "firstPartyHostnames": ["www.example.com"] },
"timings": [
{ "metric": "largest-contentful-paint", "budget": 2500 },
{ "metric": "total-blocking-time", "budget": 200 }
],
"resourceSizes": [
{ "resourceType": "document", "budget": 20 },
{ "resourceType": "stylesheet", "budget": 20 },
{ "resourceType": "font", "budget": 50 },
{ "resourceType": "script", "budget": 100 },
{ "resourceType": "total", "budget": 560 }
],
"resourceCounts": [
{ "resourceType": "third-party", "budget": 10 },
{ "resourceType": "total", "budget": 30 }
]
}
]
En Lighthouse CI, los mismos límites se escriben como aserciones en lighthouserc.json. Los tamaños de resource-summary van en bytes, no en KB: es el despiste más común al migrar. Y puedes indicar que se evalúe la mediana de varias ejecuciones:
{
"ci": {
"collect": { "numberOfRuns": 5 },
"assert": {
"assertions": {
"largest-contentful-paint": ["error", {"maxNumericValue": 2500, "aggregationMethod": "median"}],
"total-blocking-time": ["warn", {"maxNumericValue": 200, "aggregationMethod": "median"}],
"cumulative-layout-shift": ["error", {"maxNumericValue": 0.1, "aggregationMethod": "median"}],
"resource-summary:script:size": ["error", {"maxNumericValue": 102400}],
"resource-summary:total:size": ["warn", {"maxNumericValue": 573440}],
"resource-summary:third-party:count": ["warn", {"maxNumericValue": 10}]
}
}
}
}
102.400 bytes son 100 KiB y 573.440, 560 KiB, los mismos límites del budget.json. Las aserciones con error hacen fallar la comprobación; las de warn sólo avisan.
Ruta de decisión cuando el presupuesto se rompe
- ¿Se ha roto en la ruta crítica o en el resto? Si es en la crítica, el LCP está en juego: arréglalo antes de publicar.
- ¿Qué tipo de recurso ha crecido? Compáralo con la tabla de reparto. Si es la imagen LCP, recomprime o ajusta su tamaño; si es JavaScript, mira qué dependencia entró.
- ¿Aporta algo que el lector note? Si no, se quita. Si sí, se compensa recortando otra partida: el total no crece.
- ¿Hay que subir el presupuesto? Sólo con datos de campo que demuestren que el LCP real sigue por debajo del objetivo, y dejándolo anotado con fecha y motivo.
Cuándo no aplicar estas cifras tal cual
Si tu público está mayoritariamente en escritorio con fibra, la red del ejemplo es demasiado pesimista y el presupuesto puede ser más generoso; si está en zonas con redes lentas, quizá sea optimista. Si el elemento LCP es texto y no una imagen, la partida de imagen crítica desaparece y lo que pesa son CSS y fuentes. Y en una página que no aprueba Core Web Vitals por INP, recortar KB ayudará poco: el presupuesto que importa ahí es el de tiempo de ejecución de JavaScript. Rehaz el cálculo con tus supuestos; el método vale aunque los números cambien.
- Objetivo de LCP elegido y red de referencia anotada como supuesto.
- Cálculo de bytes críticos hecho con margen para arranque lento y RTT extra.
- Reparto por tipo de recurso en una tabla que conozca todo el equipo.
- Terceros fuera de la ruta crítica y con límite de peticiones.
- Espacio de anuncios reservado con
min-heightpor punto de corte. - Aserciones en Lighthouse CI con tamaños en bytes y mediana de varias ejecuciones.
Cómo se ha elaborado este artículo
El artículo se basa en el artículo «Performance budgets 101» de web.dev, en la guía de web.dev para optimizar CLS, en la documentación de limitación de red de Lighthouse, en las notas de la versión 12.0.0 de Lighthouse y en la referencia de configuración de Lighthouse CI. El cálculo del peso crítico es una estimación simplificada con supuestos explícitos (no reproduce el simulador de Lighthouse), y los repartos y tamaños de anuncio son ilustrativos. No incluye pruebas propias.
Fuentes consultadas
- web.dev: Performance budgets 101
- web.dev: Use Lighthouse for performance budgets
- web.dev: Optimize Cumulative Layout Shift
- GoogleChrome (GitHub): Lighthouse throttling
- GoogleChrome (GitHub): Release v12.0.0
- GoogleChrome (GitHub): Lighthouse CI configuration
¿Has visto un dato erróneo o desactualizado? Escribe a [email protected] indicando la URL. Las correcciones se aplican según la política editorial.