Saltar al contenido
rendimiento.html · devschool

Rendimiento web desde el HTML

Lección 29 de 39 · 14 min de lectura · Actualizado el

En esta lección
  1. Cómo carga una página
  2. El peso de la página
  3. Imágenes: el mayor ahorro
  4. Scripts: defer y async
  5. Pistas de carga: preconnect y preload
  6. Fuentes sin texto invisible
  7. Core Web Vitals: cómo mide Google la experiencia
  8. Medir: Lighthouse y PageSpeed Insights
  9. Un <head> bien ordenado para el rendimiento
  10. Errores frecuentes
  11. Resumen

Una web lenta pierde visitas: si la página tarda varios segundos en mostrar algo, mucha gente se va antes de verla, sobre todo en el móvil y con mala cobertura. El rendimiento web (web performance) es todo lo que haces para que la página llegue antes, se vea antes y responda rápido. En esta lección verás qué hace que una página pese, qué atributos de HTML ayudan al navegador a cargar lo importante primero, cómo mide Google la experiencia (las Core Web Vitals) y cómo analizar tu web con Lighthouse.

Mucho de esto se decide en el HTML, antes de escribir una sola línea de JavaScript.

Cómo carga una página

Recuerda lo que viste en cómo funciona la web: el navegador pide el HTML, lo lee de arriba abajo y, cada vez que encuentra un recurso (CSS, imagen, script, fuente), lo pide también. Con todo eso construye la página y la pinta en pantalla.

Tres ideas que debes tener claras:

  • El CSS bloquea el pintado. El navegador no muestra nada hasta tener el CSS del <head>, porque no quiere enseñarte la página sin estilos y luego cambiarla.
  • Un <script> normal bloquea la lectura del HTML. Al encontrarlo, el navegador para, lo descarga, lo ejecuta y solo después sigue leyendo.
  • Cada recurso es una petición. Si el recurso está en otro dominio, antes de descargarlo hay que buscar la dirección del servidor (DNS) y abrir una conexión segura. Eso cuesta tiempo aunque el archivo sea pequeño.

Todo lo que el navegador necesita para mostrar lo primero que ves se llama ruta crítica de renderizado (critical rendering path). La regla general del rendimiento es: que la ruta crítica sea corta y ligera, y que lo demás espere.

El peso de la página

El peso de una página es la suma de todo lo que se descarga: HTML, CSS, JavaScript, imágenes, fuentes, vídeos. Puedes verlo en las DevTools, pestaña Red (Network), abajo del todo: número de peticiones, kilobytes transferidos y tiempo de carga. Lo viste en editor y DevTools.

En una web normal, lo que más pesa suele ser, por este orden:

  1. Imágenes. Una sola foto sacada del móvil puede pesar 4 MB.
  2. JavaScript. No solo pesa: además hay que ejecutarlo, y en un móvil modesto eso tarda.
  3. Fuentes web. Cada grosor y estilo es un archivo.
  4. CSS y HTML, que normalmente son lo más ligero.

Algunas medidas sencillas que reducen el peso sin tocar el diseño:

  • Redimensiona y comprime las imágenes antes de subirlas. Una foto de portada rara vez necesita más de 1600 píxeles de ancho.
  • Usa formatos modernos: AVIF o WebP para fotos, SVG para logos e iconos.
  • No cargues librerías enteras para usar una función. Si solo necesitas un carrusel sencillo, quizá baste con CSS.
  • Limita las fuentes web: dos familias y pocos grosores. Usa el formato WOFF2, que es el más comprimido.
  • Minifica el CSS y el JavaScript (quitar espacios y comentarios). Las herramientas de construcción como Vite lo hacen solas.
  • Activa la compresión en el servidor (gzip o Brotli). La mayoría de hostings ya la tienen activada para HTML, CSS y JS.

Consejo: en la pestaña Red puedes simular una conexión lenta (menú “Sin limitación” → “4G lenta”). Prueba así tu web: es como la ve mucha gente en el móvil.

Imágenes: el mayor ahorro

Todo lo relativo a imágenes lo tienes explicado en imágenes responsive. Aquí va el resumen, porque es lo que más mejora el rendimiento:

<!-- Imagen principal, visible al abrir la página: que llegue cuanto antes -->
<img src="portada.avif" width="1600" height="700"
     fetchpriority="high" alt="Sala de bloque con presas de colores">

<!-- Imágenes de más abajo: que esperen a que el usuario se acerque -->
<img src="taller-nudos.webp" width="600" height="400"
     loading="lazy" decoding="async" alt="Monitora enseñando el nudo de ocho">
AtributoQué haceDónde usarlo
width y heightReserva el hueco antes de que llegue la imagenEn todas las imágenes
loading="lazy"No descarga la imagen hasta que se acerca a la pantallaImágenes que no se ven al abrir la página
fetchpriority="high"Pide la imagen con prioridad altaSolo la imagen principal
decoding="async"Decodifica sin bloquear el restoGalerías con muchas imágenes
srcset + sizesCada pantalla descarga el tamaño que necesitaFotos que cambian de tamaño
<picture> + typeAVIF o WebP con JPG de reservaFotos

loading="lazy" también funciona en los <iframe>. Un mapa o un vídeo de YouTube incrustado pesa bastante; si está al final de la página, que espere:

<iframe src="https://www.youtube-nocookie.com/embed/ID_DEL_VIDEO"
        width="560" height="315" loading="lazy"
        title="Vídeo: cómo asegurar en top rope"></iframe>

Cuidado: poner loading="lazy" en la imagen de portada es uno de los errores más comunes. El navegador espera a saber dónde queda en la página antes de pedirla, y la imagen más importante llega tarde.

Scripts: defer y async

Lo explicamos en el head y metadatos, así que solo recordamos la idea: un <script> sin atributos detiene la lectura del HTML. Con defer o async se descarga en paralelo.

<head>
  <!-- Tu código: se ejecuta cuando el HTML está leído, en orden -->
  <script src="js/app.js" defer></script>

  <!-- Algo independiente, como unas estadísticas: se ejecuta en cuanto llega -->
  <script src="https://estadisticas.example.com/contador.js" async></script>
</head>
Forma¿Bloquea la lectura del HTML?¿Respeta el orden?
<script src>SíSí
<script src defer>NoSí
<script src async>No (solo un momento al ejecutarse)No
<script type="module">No (se comporta como defer)Sí

Además del cómo, piensa en el cuánto. Cada script de terceros (chat, mapas, anuncios, redes sociales) añade peso y trabajo. Antes de añadir uno, pregúntate si hace falta en todas las páginas o solo en una.

Pistas de carga: preconnect y preload

Las pistas de recursos (resource hints) son etiquetas <link> en el <head> que le dan al navegador información que todavía no tiene.

preconnect: abrir la conexión antes

Si vas a pedir algo a otro dominio (una fuente de Google Fonts, un CDN de imágenes), el navegador tiene que buscar el servidor y abrir la conexión. Con preconnect lo hace mientras sigue leyendo el HTML:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

El atributo crossorigin hace falta en el segundo porque los archivos de fuentes se piden siempre en modo CORS (un modo de petición entre dominios); si no coincide, el navegador abre una conexión nueva y la primera no sirve.

Úsalo con 2 o 3 dominios como máximo, los que de verdad vas a usar enseguida. Cada conexión abierta consume recursos.

Existe una versión más ligera, dns-prefetch, que solo resuelve el nombre del dominio. Sirve para dominios que se usarán más tarde:

<link rel="dns-prefetch" href="https://mapas.example.com">

preload: descargar ya algo que se descubre tarde

Algunos recursos importantes el navegador los descubre tarde. El caso típico son las fuentes: están dentro del CSS, así que el navegador primero descarga el CSS, lo lee, ve que hay un texto con esa fuente y solo entonces la pide. Con preload la pide desde el principio:

<link rel="preload" href="/fuentes/inter-variable.woff2"
      as="font" type="font/woff2" crossorigin>
  • as indica qué tipo de recurso es (font, image, style, script…). Es obligatorio: sin él el navegador no sabe qué prioridad darle.
  • Las fuentes llevan siempre crossorigin, aunque estén en tu propio dominio.

Otro uso habitual: una imagen de portada que se pone como fondo desde el CSS (background-image), que el navegador no ve en el HTML.

<link rel="preload" href="img/portada.avif" as="image" type="image/avif" fetchpriority="high">

Cuidado: preload no es gratis. Lo que precargas compite con lo demás por la conexión. Si precargas algo que la página no usa en los primeros segundos, la consola muestra un aviso y has empeorado la carga. Reserva preload para uno o dos recursos críticos.

PistaQué adelantaCuándo
dns-prefetchBuscar la dirección del dominioDominios que usarás más tarde
preconnectBúsqueda + conexión seguraDominios que usarás enseguida (2-3 como máximo)
preloadLa descarga de un recurso concretoFuentes o imágenes críticas que se descubren tarde

Fuentes sin texto invisible

Mientras se descarga una fuente web, algunos navegadores esconden el texto. Con font-display: swap en la regla @font-face se muestra primero con una fuente del sistema y se cambia cuando llega la buena. Si usas Google Fonts, añade &display=swap a la URL (ya viene por defecto en el código que te dan). Tienes los detalles en fuentes web.

Core Web Vitals: cómo mide Google la experiencia

Google resume la experiencia de carga en tres métricas, las Core Web Vitals. Las usa como una de las señales para ordenar los resultados de búsqueda, pero sobre todo son una buena forma de saber si tu web va bien.

MétricaQué mideBuenoMalo
LCP (Largest Contentful Paint)Cuánto tarda en verse el elemento más grande de la pantalla inicial≤ 2,5 s> 4 s
CLS (Cumulative Layout Shift)Cuánto se mueve el contenido mientras carga≤ 0,1> 0,25
INP (Interaction to Next Paint)Cuánto tarda la página en reaccionar cuando pulsas o escribes≤ 200 ms> 500 ms

Entre “bueno” y “malo” está la zona de “necesita mejorar”. Google considera que una página aprueba si el 75 % de las visitas reales están en verde.

LCP: que lo principal se vea pronto

El elemento del LCP suele ser la foto de portada o el titular principal. Para mejorarlo:

  • Que la imagen esté en el HTML con <img> (no metida por JavaScript) y con fetchpriority="high".
  • Nada de loading="lazy" en ella.
  • Que pese poco: AVIF o WebP, tamaño ajustado con srcset.
  • Que el servidor responda rápido y el CSS no sea enorme.

CLS: que nada salte

Cada vez que algo aparece y empuja al resto, suma CLS. Las causas típicas:

  • Imágenes, vídeos e iframes sin width y height.
  • Banners (cookies, avisos) que se insertan arriba del contenido cuando ya se ve.
  • Fuentes web que cambian mucho el tamaño del texto al llegar.
  • Anuncios o incrustados sin un hueco reservado.

La solución casi siempre es reservar el espacio antes: width y height, un min-height en el hueco del anuncio, o mostrar los avisos encima del contenido en lugar de empujarlo.

INP: que responda al instante

INP sustituyó en 2024 a la antigua métrica FID. Mide el retraso entre una interacción (un clic, una tecla) y el momento en que la pantalla cambia. Se estropea cuando hay mucho JavaScript ejecutándose a la vez. Desde el HTML ayudas cargando menos scripts y con defer; el resto se trabaja en JavaScript (dividir tareas largas, no hacer cálculos pesados en cada evento). Lo verás en el curso de JavaScript.

Medir: Lighthouse y PageSpeed Insights

Lighthouse

Lighthouse es una herramienta que viene en Chrome (DevTools, pestaña Lighthouse). Carga tu página simulando un móvil con una conexión lenta y te da una nota de 0 a 100 en cuatro categorías: Performance (rendimiento), Accessibility, Best Practices y SEO.

Cómo usarlo bien:

  1. Abre la página en una ventana de incógnito, para que las extensiones no afecten al resultado.
  2. Elige Mobile y la categoría Performance.
  3. Pulsa Analyze page load.
  4. Mira las métricas (LCP, CLS, Total Blocking Time…) y, sobre todo, la lista de diagnósticos: te dice qué imagen pesa demasiado, qué script bloquea o qué elemento es el LCP.

Nota: Lighthouse no puede medir INP de verdad, porque nadie interactúa con la página durante la prueba. En su lugar muestra el TBT (Total Blocking Time): el tiempo que el JavaScript tuvo bloqueada la página. Si el TBT es alto, el INP probablemente también lo será.

Datos de laboratorio y datos reales

Lighthouse da datos de laboratorio: una prueba en condiciones controladas. Es útil para encontrar problemas, pero la nota cambia un poco cada vez que lo ejecutas.

PageSpeed Insights (pagespeed.web.dev) muestra, además, datos de campo: las métricas reales de los usuarios de Chrome que visitaron tu web en los últimos 28 días, si tiene suficientes visitas. Esos son los que Google tiene en cuenta. Si tu web es nueva o pequeña, solo verás los de laboratorio.

Consejo: no persigas el 100. Una página con 90 en Lighthouse y las tres Core Web Vitals en verde está bien. Es mejor dedicar el tiempo a quitar la imagen de 3 MB que a rascar los últimos puntos.

Un <head> bien ordenado para el rendimiento

Juntando lo visto, así podría quedar la cabecera de la web de un rocódromo:

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Rocódromo La Fisura | Escalada en Santander</title>

  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link rel="preload" href="/fuentes/inter-variable.woff2" as="font" type="font/woff2" crossorigin>

  <link rel="stylesheet" href="/css/estilos.css">
  <script src="/js/app.js" defer></script>
</head>

Y en el <body>, la imagen de portada con fetchpriority="high" y dimensiones, y el resto de imágenes con loading="lazy".

Errores frecuentes

  • loading="lazy" en la imagen principal. Retrasa justo el elemento que mide el LCP. Úsalo solo en lo que está más abajo.
  • fetchpriority="high" en muchas imágenes. Si todo es prioritario, nada lo es. Una imagen por página.
  • Precargar demasiado. Cada preload compite con el resto. Si la consola avisa de que un recurso precargado no se usó, quítalo.
  • Olvidar crossorigin al precargar fuentes. El navegador descarga la fuente dos veces: la precargada no le sirve.
  • Imágenes sin width y height. Es la causa número uno de CLS.
  • Subir las fotos tal cual salen de la cámara. Varios megas por imagen. Redimensiona y convierte a AVIF o WebP.
  • Scripts sin defer en el <head>. Bloquean la lectura del HTML y retrasan todo.
  • Medir solo en tu ordenador con fibra. Prueba con la simulación de móvil y red lenta, que es lo que usa Lighthouse.

Resumen

HerramientaPara qué
Pestaña Red de las DevToolsVer el peso, el número de peticiones y el orden de carga
width / height en imágenesEvitar saltos (CLS)
loading="lazy"Retrasar imágenes e iframes de más abajo
fetchpriority="high"Adelantar la imagen principal (LCP)
AVIF / WebP + srcsetImágenes más ligeras y del tamaño justo
defer / asyncScripts que no bloquean
preconnect / dns-prefetchAdelantar conexiones con otros dominios
preloadAdelantar fuentes o imágenes críticas que se descubren tarde
font-display: swapTexto visible mientras carga la fuente
LCP / CLS / INPLas tres Core Web Vitals: carga, estabilidad y respuesta
LighthousePrueba de laboratorio con diagnósticos
PageSpeed InsightsDatos reales de usuarios (si hay suficientes visitas)

En la siguiente lección verás cómo describir el contenido de tu página para que Google lo entienda mejor: datos estructurados con JSON-LD.

Pruébalo tú

Cambia el código y pulsa Ejecutar (o Ctrl + Enter).

rendimiento.html
Resultado

Pon a prueba lo que has aprendido

[HTML] ¿Qué atributo debe llevar la imagen principal de la portada para cargar cuanto antes?

[HTML] ¿Cuál es la causa más común de CLS (saltos de diseño)?

[HTML] ¿Qué diferencia hay entre <script defer> y <script async>?

[HTML] ¿Qué mide INP?

¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.