Saltar al contenido
tipografias-web.css · devschool

Fuentes web con @font-face

Lección 8 de 25 · 11 min de lectura · Actualizado el

En esta lección
  1. Familias genéricas y pilas de fuentes
  2. @font-face: tus propias fuentes
  3. Google Fonts
  4. Fuentes variables
  5. Las propiedades de la fuente
  6. Tamaños fluidos con clamp()
  7. Errores frecuentes
  8. Resumen

En la lección de textos y tipografía aprendiste a cambiar la fuente con font-family y a controlar tamaños, alineación y decoración. Aquí vamos un paso más allá: cómo usar tipografías que el usuario no tiene instaladas, cómo cargarlas sin que la página vaya lenta y cómo hacerlo respetando la privacidad de tus visitantes. También verás las fuentes variables y los tamaños de letra fluidos.

Familias genéricas y pilas de fuentes

Cuando escribes font-family, el navegador solo puede usar fuentes que existan en el ordenador del visitante o que tú le hayas enviado. Por eso siempre se escribe una lista (una pila): si la primera no está, prueba la siguiente.

La lista debe terminar con una familia genérica, que el navegador siempre sabe resolver:

Familia genéricaQué esEjemplo típico
serifLetras con rematesTimes, Georgia
sans-serifLetras sin rematesArial, Helvetica
monospaceTodas las letras miden lo mismoConsolas, Courier
system-uiLa fuente de la interfaz del sistemaSegoe UI, San Francisco, Roboto
ui-monospaceLa monoespaciada del sistemaSF Mono, Cascadia
cursive, fantasyManuscritas y decorativasPoco predecibles, evítalas

Pilas de fuentes del sistema

Una opción muy profesional es no descargar ninguna fuente y usar la del sistema operativo. La web carga al instante y se ve “nativa” en cada dispositivo:

body {
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

code, pre {
  font-family: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, monospace;
}

.titular {
  /* Pila con remates que existe en casi todos los sistemas */
  font-family: Charter, "Bitstream Charter", "Sitka Text", Cambria, Georgia, serif;
}

¿Por qué tantos nombres? Porque cada sistema llama distinto a su fuente: Segoe UI en Windows, -apple-system en Safari antiguo, Roboto en Android. El navegador usa el primero que encuentra.

@font-face: tus propias fuentes

Si quieres una tipografía concreta, tienes que enviarla al navegador junto con la página. Se hace con la regla @font-face, que declara una familia nueva y dice dónde está el archivo:

@font-face {
  font-family: "Lora";                                /* el nombre que usarás luego */
  src: url("../fuentes/lora-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Lora";
  src: url("../fuentes/lora-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

body {
  font-family: "Lora", Georgia, serif;   /* Georgia mientras carga o si falla */
}

Fíjate en que las dos reglas usan el mismo font-family. Así, cuando escribas font-weight: 700 en un <strong>, el navegador elegirá el archivo de negrita. Si no declaras la negrita, el navegador la inventa engordando la normal (“negrita sintética”), y queda peor.

Las partes de @font-face

  • font-family: el nombre que tú eliges. No tiene que coincidir con el del archivo.
  • src: la ruta al archivo con url() y su formato con format(). Como en los fondos, la ruta es relativa al archivo CSS.
  • font-weight y font-style: qué grosor y estilo contiene ese archivo.
  • font-display: qué hacer mientras la fuente se descarga.

El formato: woff2

Hoy solo necesitas woff2. Es un formato comprimido pensado para la web y lo entienden todos los navegadores actuales. Los antiguos .ttf, .eot o .svg ya no hacen falta. Si tienes una fuente en .ttf, conviértela a .woff2 con una herramienta de conversión: pesará bastante menos.

font-display: swap

Mientras la fuente se descarga, el navegador tiene que decidir qué enseñar:

ValorQué pasa mientras carga
autoLo decide el navegador (suele esconder el texto hasta 3 s)
blockTexto invisible un rato, luego la fuente
swapMuestra enseguida la fuente de reserva y la cambia al llegar
fallbackEspera muy poco; si tarda, se queda con la de reserva
optionalSolo usa la fuente si llega casi al instante

swap es la opción más habitual para el texto: el contenido se lee desde el primer momento. El precio es un pequeño “salto” cuando llega la fuente buena. Para reducirlo, elige una fuente de reserva de tamaño parecido.

Google Fonts

Google Fonts ofrece cientos de fuentes libres. La forma rápida de usarlas es enlazar su CSS:

<head>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
</head>
body { font-family: "Inter", system-ui, sans-serif; }

Qué hace cada línea:

  • Los dos preconnect abren la conexión con los servidores de Google antes de necesitarlos. Se ahorra tiempo porque el CSS está en un dominio y los archivos de fuente en otro (fonts.gstatic.com, que exige crossorigin).
  • El enlace trae una hoja de estilos con los @font-face ya escritos. En la URL eliges la familia, los grosores (wght@400;700) y display=swap.

Consejo: pide solo los grosores que uses. Cada grosor es un archivo más que descargar. Dos familias con dos o tres grosores cada una es más que suficiente.

Alojar las fuentes tú mismo

El enlace de Google es cómodo, pero tiene dos problemas:

  1. Rendimiento. El navegador tiene que conectarse a otros dos dominios. Desde hace años los navegadores no comparten la caché entre webs, así que ya no hay ventaja por “tenerla guardada de otra página”.
  2. Privacidad y RGPD. Cada visita envía la dirección IP del usuario a Google sin su consentimiento. En enero de 2022, un tribunal regional de Múnich condenó al dueño de una web a indemnizar a un visitante por este motivo, al considerar que se habían cedido datos personales sin base legal. Desde entonces es habitual en Europa descargar las fuentes y servirlas desde tu propio servidor.

Alojarlas tú es sencillo:

  1. Descarga los archivos .woff2 (desde la propia web de Google Fonts o con herramientas como google-webfonts-helper).
  2. Cópialos a una carpeta de tu proyecto, por ejemplo fuentes/.
  3. Escribe tus @font-face como en el apartado anterior.
  4. Quita los <link> a Google.

Si quieres que la fuente principal llegue lo antes posible, puedes adelantar su descarga desde el HTML:

<link rel="preload" href="/fuentes/inter-variable.woff2" as="font" type="font/woff2" crossorigin>

Usa preload solo con una o dos fuentes críticas; si precargas todo, no ganas nada.

Fuentes variables

Una fuente clásica necesita un archivo por grosor: fina, normal, seminegrita, negrita… Una fuente variable mete todos los grosores (y a veces otras variaciones) en un solo archivo. Suele pesar menos que tres o cuatro archivos sueltos y te deja usar cualquier valor intermedio.

En @font-face, el grosor se indica como un rango:

@font-face {
  font-family: "Inter";
  src: url("../fuentes/inter-variable.woff2") format("woff2");
  font-weight: 100 900;   /* este archivo cubre del 100 al 900 */
  font-style: normal;
  font-display: swap;
}

h1     { font-weight: 800; }
h2     { font-weight: 650; }  /* valores intermedios: solo con fuentes variables */
.fina  { font-weight: 300; }

Las fuentes variables también pueden tener otros ejes, como la anchura (wdth) o la inclinación (slnt). Para ejes no estándar existe font-variation-settings, pero para el grosor usa siempre font-weight, que es más claro.

Las propiedades de la fuente

font-weight: el grosor

Va de 100 a 900. Los nombres normal y bold equivalen a 400 y 700.

ValorNombre habitual
100Thin (fina)
300Light (ligera)
400Regular (normal)
500Medium
600SemiBold
700Bold (negrita)
800-900ExtraBold, Black

Si pides font-weight: 600 y solo has cargado 400 y 700, el navegador usa el más cercano según unas reglas fijas (normalmente 700).

font-style: cursiva

em       { font-style: italic; }
.normal  { font-style: normal; }

Con fuentes web, la cursiva es otro archivo (o un eje de la variable). Si no la cargas, el navegador inclina la normal y el resultado es una cursiva falsa.

line-height: el interlineado

body { line-height: 1.6; }    /* sin unidades: 1,6 veces el tamaño de cada elemento */
h1   { line-height: 1.15; }

Escríbelo sin unidades. Con line-height: 24px o 1.5em, los hijos heredan un valor fijo calculado en el padre; si un hijo tiene letra más grande, las líneas se montan. Sin unidades, cada elemento lo recalcula con su propio tamaño.

letter-spacing y text-transform

.etiqueta {
  text-transform: uppercase;   /* MAYÚSCULAS sin cambiar el HTML */
  letter-spacing: 0.1em;       /* más aire entre letras */
  font-size: 0.75rem;
}
h1 { letter-spacing: -0.02em; } /* titulares grandes, algo más juntos */

Usa em en letter-spacing para que el espaciado crezca con la letra. Las mayúsculas pequeñas se leen mejor con algo de espacio extra; los titulares grandes, con un poco menos.

text-transform admite uppercase, lowercase y capitalize (primera letra de cada palabra). Úsalo en vez de escribir el texto en mayúsculas en el HTML: los lectores de pantalla a veces deletrean las palabras en mayúsculas.

El atajo font

body {
  font: italic 700 1rem/1.6 "Lora", Georgia, serif;
  /*    estilo grosor tamaño/interlineado familia */
}

El tamaño y la familia son obligatorios y van al final. Como todos los atajos, reinicia lo que no escribas.

Tamaños fluidos con clamp()

En la lección de unidades viste clamp(mínimo, ideal, máximo). En tipografía se usa para que los titulares crezcan con la pantalla sin pasarse:

h1 {
  font-size: clamp(1.75rem, 1rem + 3vw, 3rem);
}
  • En un móvil de 360 px: 1rem + 3vw = 16 + 10,8 = 26,8 px, menos que el mínimo, así que se queda en 28 px (1.75rem).
  • En una tableta de 768 px: 16 + 23 = 39 px.
  • En un portátil de 1440 px: 16 + 43 = 59 px, más que el máximo, así que se queda en 48 px (3rem).

¿Por qué 1rem + 3vw y no solo 5vw? Porque un valor solo en vw no crece al hacer zoom: si el usuario amplía la página, el texto sigue igual. Sumar una parte en rem mantiene la accesibilidad.

Cuidado: usa tamaños fluidos en titulares. Para el texto de los párrafos, 1rem (o algo un poco mayor) es casi siempre la mejor elección.

Errores frecuentes

  • Olvidar la familia genérica final. Si la fuente web falla, el navegador pone su fuente por defecto (a menudo Times). Termina siempre con serif, sans-serif o monospace.
  • Nombres distintos en @font-face y en font-family. Si declaras "Lora" y usas "lora-regular", no se aplica.
  • Rutas mal escritas en src. La ruta es relativa al CSS. Mira la pestaña Red de las herramientas de desarrollo: una fuente con error 404 salta a la vista.
  • Cargar demasiados grosores y familias. Cada archivo son decenas de KB. Revisa qué grosores usas de verdad.
  • No cargar la negrita o la cursiva. El navegador las falsifica y se nota.
  • line-height con px. Rompe los interlineados de los hijos con otro tamaño de letra.
  • Tamaños solo en vw. No respetan el zoom del usuario.
  • Usar Google Fonts por enlace sin pensarlo en una web europea. Valora alojarlas tú.

Resumen

ConceptoPara qué sirveEjemplo
Pila de fuentesAlternativas si falta una"Inter", system-ui, sans-serif
system-uiFuente del sistema, sin descargafont-family: system-ui, sans-serif
@font-faceDeclarar una fuente propiasrc: url(...) format("woff2")
woff2Formato de fuente para la weblora-regular.woff2
font-display: swapMostrar texto mientras cargaDentro de @font-face
preconnect / preloadAdelantar conexiones o descargas<link rel="preload" as="font">
Fuente variableTodos los grosores en un archivofont-weight: 100 900
font-weightGrosor400, 700, 650
font-styleCursivaitalic
line-heightInterlineado, sin unidades1.6
letter-spacingEspacio entre letras0.1em
text-transformMayúsculas y minúsculasuppercase
clamp()Tamaño fluido con límitesclamp(1.75rem, 1rem + 3vw, 3rem)

Ya sabes elegir y cargar tipografías. A continuación empieza la maquetación de verdad: el modelo de caja.

Pruébalo tú

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

tipografias-web.html
Resultado

Pon a prueba lo que has aprendido

[CSS] ¿Qué hace font-display: swap dentro de un @font-face?

[CSS] Con este CSS, ¿qué pasa en un <strong> dentro de un párrafo?
@font-face {
  font-family: "Lora";
  src: url("lora-regular.woff2") format("woff2");
  font-weight: 400;
}
p { font-family: "Lora", Georgia, serif; }

[CSS] ¿Qué indica font-weight: 100 900; dentro de un @font-face?

[CSS] ¿Por qué se recomienda clamp(1.75rem, 1rem + 3vw, 3rem) en lugar de font-size: 5vw para un titular?

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