Una fuente web tarda en descargarse. Mientras tanto el navegador tiene dos opciones malas: dejar el texto invisible (el «parpadeo de texto invisible») o mostrarlo con otra fuente y cambiarla de golpe al llegar (y el texto salta). Con cuatro decisiones bien tomadas tendrás fuentes web sin parpadeo y sin saltos. Lo medimos con una fuente real servida con 1.2 segundos de retraso.
También te puede interesar
1. font-display: qué hacer mientras llega
Servimos Noto Serif con 1.2 s de retraso y medimos el ancho del mismo título a los 300 ms y al final, con las tres opciones principales, en los tres motores:
ancho del texto a los 300 ms → al finalchromium block: 510 → 593 px swap: 510 → 593 px optional: 510 → 510 px firefox block: 510 → 593 px swap: 510 → 593 px optional: 510 → 510 px webkit block: 510 → 593 px swap: 510 → 593 px optional: 510 → 593 px
block: el texto queda invisible hasta que llega la fuente (hasta 3 segundos) y luego aparece con ella. Mientras tanto ocupa el lugar que tendría con la de respaldo (510 px) y al llegar la fuente cambia a 593 px. Úsalo solo en íconos hechos con fuentes, donde la letra de respaldo no tiene sentido.swap: se ve de inmediato con la de respaldo y se cambia al llegar. Es lo más usado, pero el ancho cambia: de 510 a 593 px, igual en los tres motores. Ese cambio empuja el texto que sigue (CLS).optional: si la fuente no está lista casi al instante, esa visita se queda con la de respaldo y la web se usa en la siguiente, cuando ya está guardada. En Chromium y Firefox el texto se quedó en 510 px: cero saltos. En WebKit, en cambio, se comportó comoswapy cambió a 593 px al llegar la fuente. Es buena opción para el texto de los artículos, sabiendo que la primera visita puede no ver tu fuente.
2. Una fuente de respaldo del mismo tamaño: size-adjust
El salto de swap se reduce si la fuente de respaldo ocupa lo mismo que la web. @font-face permite declarar una fuente local con size-adjust (y, si hace falta, ascent-override y descent-override para la altura de línea). Con el ancho medido calculamos el ajuste (116.3 %) y repetimos la prueba:
swap con el respaldo ajustado: ancho a los 300 ms → al finalchromium 610 → 593 px firefox 510 → 593 px webkit 593 → 593 px
El resultado no fue igual en los tres, y vale la pena contarlo tal cual:
- WebKit: el ancho no cambió nada al llegar la fuente web. Es el efecto buscado.
- Chromium: el respaldo ajustado quedó un poco más ancho que la fuente web (610 frente a 593 px). El salto se redujo de 83 a 17 px, pero no desapareció.
- Firefox: no usó la fuente local declarada con
local()y se quedó con la de respaldo normal, así que el salto fue el mismo que sin ajuste. No averiguamos por qué; si tu respaldo depende delocal(), pruébalo en Firefox.
Moraleja: size-adjust ayuda, pero comprueba el resultado en cada navegador. Hay herramientas que calculan estos valores por ti a partir de las dos fuentes (por ejemplo, Fontaine o el ajuste automático de fuentes de Next.js).
3. woff2 y subconjuntos: que pese poco
La misma fuente, Noto Serif Regular, en tres formatos:
tamaño del archivoTTF original: 575 KB woff2 (comprimida): 186 KB woff2 solo con letras latinas: 27 KB
woff2 es el formato que entienden todos los navegadores actuales: no hace falta servir TTF, WOFF ni EOT. Y si tu sitio está en español, no necesitas los alfabetos griego, cirílico o vietnamita que trae la fuente completa: un subconjunto con el latín básico y sus acentos pesa una fracción. unicode-range le dice al navegador para qué caracteres sirve cada archivo, y solo descarga los que usa la página.
4. preload: pedirla antes
<link rel="preload" href="/fuentes/noto-serif-latin.woff2" as="font" type="font/woff2" crossorigin>
El navegador no sabe que necesita la fuente hasta que lee el CSS y encuentra texto que la usa. <link rel="preload"> en el <head> la pide desde el principio. Lleva crossorigin siempre, aunque la fuente esté en tu mismo dominio: sin él, el navegador la descarga dos veces. Precarga solo la fuente del texto principal; precargar todas retrasa lo demás.
Todo junto
@font-face {
font-family: "Noto Serif";
src: url("/fuentes/noto-serif-latin.woff2") format("woff2");
font-display: swap; /* mientras llega, texto con la de respaldo */
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+2000-206F, U+20AC;
}
/* La de respaldo, ajustada para que ocupe lo mismo que la web */
@font-face {
font-family: "Respaldo de Noto Serif";
src: local("Times New Roman"), local("Liberation Serif");
size-adjust: 109%;
}
body {
font-family: "Noto Serif", "Respaldo de Noto Serif", serif;
}Cada fragmento de HTML de esta página pasó por el Nu Html Checker 26.11.4 (el validador del W3C) y cada resultado se pintó y se midió en Chromium, Firefox y WebKit antes de publicarla. Prueba tus cambios en el editor de HTML y CSS o aprende desde cero con el curso.