wandres.dev
FUENTES Y RENDIMIENTO · El texto que aparece rápido

La fuente del sistema y el árbol de decisión completo

Qué resuelve la familia genérica del sistema y qué cuesta exactamente no usarla, el patrón híbrido de sistema para el cuerpo y fuente propia para los titulares, y la configuración final por tipo de sitio.

⏱ 18 min

Todo lo anterior —la cadena, los periodos, la precarga, los subconjuntos— existe para mitigar un coste que se puede evitar por completo con una decisión de diseño. La fuente del sistema no tiene cadena de carga, no tiene periodo de bloqueo, no desplaza nada, pesa cero bytes y cubre todos los alfabetos del mundo. No es la respuesta correcta para todos los sitios, y es la respuesta correcta para bastantes más de los que la usan.

🎯 Al terminar esta lección sabrás
  • Escribir una pila de fuentes del sistema que funcione en todas las plataformas.
  • Cuantificar exactamente qué cuesta una fuente propia frente a la del sistema.
  • Aplicar el patrón híbrido de sistema para el cuerpo y fuente propia para los titulares.
  • Resolver la configuración tipográfica de un sitio con el árbol de decisión.

La pila del sistema

CSS define una familia genérica que resuelve a la fuente de interfaz del sistema operativo: system-ui. Está disponible en los tres motores y es la forma correcta de pedirla.

Aun así, la mayoría de los equipos escribe una pila explícita detrás, y hay una razón concreta: en algunas combinaciones de sistema y configuración regional, la resolución de system-ui ha dado resultados pobres para escrituras no latinas, componiendo texto que debería ir en una fuente del sistema con una elección de reserva mala. La pila explícita sirve de red.

:root {
  --pila-sistema:
    system-ui,
    -apple-system,
    'Segoe UI',
    Roboto,
    'Helvetica Neue',
    'Noto Sans',
    'Liberation Sans',
    Arial,
    sans-serif,
    'Apple Color Emoji',
    'Segoe UI Emoji';

  --pila-mono:
    ui-monospace,
    'SF Mono',
    Menlo,
    Consolas,
    'Liberation Mono',
    monospace,
    monospace;
}

body { font-family: var(--pila-sistema); }
code, pre { font-family: var(--pila-mono); }

Dos detalles de esa pila que no son adorno.

Las familias de emoji van al final, después de la genérica. Una familia posterior a sans-serif no es código muerto: el emparejamiento de fuentes es por carácter, no por elemento, así que la genérica cubre las letras y las entradas de emoji cubren los caracteres que la genérica no tiene. Sin ellas, los emoji los resuelve la reserva del sistema, que en algunas configuraciones los pinta en monocromo.

El monospace duplicado del final es un remedio a una peculiaridad antigua. Cuando la familia resuelta de un elemento es exactamente la genérica monospace, los navegadores aplican un tamaño de fuente por defecto distinto y más pequeño que el del resto del texto, herencia de los primeros años de la web. Repetir la genérica hace que la familia declarada deje de ser exactamente esa y el tamaño se comporta con normalidad. Es feo y funciona.

CSS define además otras genéricas de interfaz —ui-sans-serif, ui-serif, ui-monospace y ui-rounded— cuya disponibilidad es desigual entre motores. Ponerlas primero en la pila es seguro, porque una genérica que el navegador no reconoce simplemente se salta.

Qué cuesta exactamente no usarla

Las cifras concretas de una configuración típica y bien optimizada: una fuente variable, subconjunto latino, autoalojada, precargada, con la reserva ajustada.

Concepto Coste
Bytes de red 25-45 KB
Peticiones adicionales 1, a veces 2
Retraso hasta el primer glifo real 250-600 ms en móvil p75
Riesgo de CLS Entre 0 y 0,15 según la configuración
Trabajo de mantenimiento Recalcular métricas y subconjuntos en cada cambio

Y esa es la versión buena. La configuración por defecto de mucha gente —dos pesos estáticos, servidos por un tercero, sin precarga, sin ajuste de la reserva— cuesta el triple de bytes, dos negociaciones de conexión, más de un segundo hasta el primer glifo real y una décima de CLS.

La fuente del sistema cuesta cero en las cinco filas. Esa es toda la comparación.

Hay una sexta ventaja que no aparece en las tablas y que en un producto internacional pesa más que todas las demás: la fuente del sistema cubre todos los alfabetos. Tu fuente propia con subconjunto latino no tiene chino, ni árabe, ni devanagari, ni cirílico si no lo incluiste. Los usuarios que escriben en esos sistemas ven la fuente de reserva de todas formas, es decir, la del sistema. Si buena parte de tu audiencia va a ver la del sistema sí o sí, la pregunta de si merece la pena el aparato para el resto cambia bastante.

El patrón híbrido

La opción intermedia, y la que suele resolver la tensión entre diseño y rendimiento: la fuente del sistema para el cuerpo del texto y una fuente propia solo para los titulares.

La lógica es que la identidad tipográfica de un sitio la lleva la fuente de titulares, no la del cuerpo. El cuerpo de texto en la fuente del sistema se lee perfectamente y casi nadie lo nota; un titular en la fuente del sistema sí se nota.

Y los números acompañan, porque un subconjunto para titulares es minúsculo: los titulares usan pocos caracteres, solo un peso o dos, y casi nunca necesitan cursivas ni el rango extendido.

@font-face {
  font-family: 'Display';
  src: url('/fuentes/display-latin.woff2') format('woff2');
  font-weight: 700;
  font-display: swap;
  unicode-range: U+0000-00FF, U+2000-206F;
}

h1, h2, h3, .titular {
  font-family: 'Display', var(--pila-sistema);
  line-height: 1.15;
}

body {
  font-family: var(--pila-sistema);
  line-height: 1.5;
}

Con esa configuración, el fichero suele quedar entre 8 y 15 KB, hay una sola petición, el swap es aceptable porque los titulares son pocos elementos, y el CLS que produce se acota con los descriptores de ajuste sobre la pila del sistema. El coste baja a una fracción y la identidad visual se conserva casi entera.

Un ajuste que mejora mucho el resultado y que cuesta una línea: fija line-height con un número en los titulares. Es donde el intercambio más desplaza, porque un titular de tres líneas que pasa a cuatro mueve una altura de línea completa a 40 píxeles de tamaño.

Nadie mide el lado del beneficio, y esa es la razón de que la discusión sobre fuentes nunca se resuelva

La conversación sobre tipografía y rendimiento se atasca siempre en el mismo punto, y es porque solo uno de los dos lados tiene números. Rendimiento llega con kilobytes, milisegundos y décimas de métrica. Diseño llega con la identidad de marca, que es real y no tiene unidades. En esa asimetría gana quien tenga más poder político, no quien tenga razón.

Hay una forma de desbloquearla que funciona, y consiste en poner números en el otro lado.

La prueba de la captura. Renderiza la página con la fuente real y con la reserva del sistema bien ajustada con los descriptores de métrica, a tamaño real, en el dispositivo de referencia. Enseña las dos capturas sin decir cuál es cuál y pide que las distingan. He hecho este ejercicio muchas veces y el resultado tiene una regularidad notable: con el cuerpo de texto, los diseñadores aciertan y nadie más; con los titulares, acierta todo el mundo.

Ese resultado es exactamente el argumento a favor del patrón híbrido, y llega con evidencia en lugar de con opinión.

La segunda pregunta, que es la buena: qué está comprando en concreto esta fuente. Casi nunca es “la identidad”. Casi siempre son una o dos propiedades concretas, y todas se pueden aislar:

Una altura de equis grande, para densidad de información. Se consigue con la fuente del sistema y un font-size-adjust calibrado.

Cifras tabulares que alinean en columnas. Es una característica de composición, no una fuente: font-variant-numeric: tabular-nums funciona con muchas fuentes del sistema.

Una forma distintiva en unos pocos caracteres. Entonces el sitio donde importa es el logotipo y los titulares, y esos son diez kilobytes.

Corresponder con la aplicación móvil. Argumento legítimo y que hay que pesar contra el coste, porque la coherencia entre plataformas tiene valor real.

Y la tercera, que es la que cierra: cuánto se paga por ella, en la unidad que le importe a quien decide. Traduce los 600 milisegundos y la décima de CLS a la métrica de negocio que tu organización mire. Si tienes datos propios que correlacionen velocidad con conversión, úsalos; si no, la cifra de bytes por visita multiplicada por el tráfico mensual suele bastar para que la conversación deje de ser abstracta.

El objetivo de todo esto no es eliminar la fuente. Es que la decisión se tome con las dos columnas visibles. En la mitad de los casos que he visto, el resultado fue conservar la fuente y reducir de cuatro pesos a uno variable con subconjunto, que es un compromiso que nadie propone cuando la discusión es “quitarla o no quitarla”.

Y una observación final sobre el propio oficio: la fuente del sistema es la elección profesional por defecto en las herramientas. Las interfaces de los sistemas operativos, los editores de código, los paneles de administración de las plataformas grandes: casi todos usan la fuente del sistema, y no por descuido. Se lee mejor porque el sistema la ha optimizado para su propio rasterizador, es la que el usuario tiene calibrada en sus ajustes de accesibilidad, y respeta las preferencias de tamaño y contraste que ha configurado. Para un producto de herramienta, empezar por ahí no es una concesión al rendimiento: es la decisión de diseño correcta que además sale gratis.

El árbol de decisión

Cuatro preguntas resuelven la configuración tipográfica de casi cualquier sitio.

¿La tipografía es parte del producto o del envoltorio? En una herramienta, un panel, una documentación o una aplicación interna, es envoltorio: pila del sistema y se acabó el nivel. En un sitio editorial o de marca, es producto y hay que seguir.

¿Los titulares bastan para llevar la identidad? Casi siempre sí. Entonces el patrón híbrido: fuente propia solo para titulares, con subconjunto ajustado y font-display: swap, y pila del sistema para el cuerpo.

Si el cuerpo necesita fuente propia, ¿cuántos pesos? Uno o dos, estáticos. Tres o más, variable con el eje recortado. En los dos casos, un solo fichero por bloque de escritura, autoalojado, con subconjunto por rango de Unicode.

¿Qué política de aparición? optional con precarga si la tasa de acierto medida lo permite, fallback si no, y siempre con la familia de reserva ajustada para que el usuario al que le falle el plazo vea una página que se parece a la buena.

La lista de comprobación que cierra el nivel, para pegar en la revisión de cada despliegue:

  • Cada regla @font-face declara font-display explícitamente.
  • Los ficheros están autoalojados y se sirven en WOFF2 con caché inmutable.
  • Hay como mucho una precarga de fuente, con crossorigin, y sin descargas duplicadas.
  • Hay un subconjunto por rango de Unicode, generado en compilación, no recortado por caracteres observados.
  • La familia de reserva está ajustada con size-adjust y los overrides, con una entrada por plataforma.
  • line-height está fijado con un número en el cuerpo y en los titulares.
  • El total de bytes de fuente por página está por debajo de 60 KB.
  • El desplazamiento medido del intercambio está por debajo de cinco píxeles.
⚔️ Reto práctico

Haz la prueba de la captura con tu propio equipo: la misma página con la fuente real y con la reserva ajustada, a tamaño real, en un móvil. Anota cuántos aciertan en el cuerpo y cuántos en los titulares. Con ese dato y la tabla de costes de esta lección, propón una configuración concreta y llévala a la siguiente revisión de diseño. Es una conversación de veinte minutos que suele ahorrar cincuenta kilobytes en cada carga de página durante años.