Construir una escala modular fluida
Dos progresiones geométricas, una por extremo, interpoladas paso a paso: la tabla completa, los cinco clamps derivados y cómo generarlos en CSS con pow().
Una escala modular es una progresión geométrica de tamaños: cada paso es el anterior multiplicado por una razón fija. La versión fluida no es una escala con vw metido dentro, es dos escalas —una para el extremo estrecho y otra para el ancho— con una recta entre cada par de pasos correspondientes. Eso permite algo que una escala única no puede: que la jerarquía se abra al crecer la pantalla en lugar de limitarse a escalar en bloque.
- Construir una progresión geométrica de tamaños a partir de una base y una razón.
- Derivar los
clamp()de cada paso a partir de dos escalas completas. - Justificar por qué la razón del extremo ancho debe ser mayor.
- Generar la escala en CSS con
pow()en lugar de a mano.
Qué es una escala modular
Eliges una base y una razón, y cada paso multiplica por la razón. Las razones habituales vienen de los intervalos musicales porque históricamente es de donde las tomó la tipografía:
| razón | nombre | carácter |
|---|---|---|
| 1.125 | segunda mayor | escala muy compacta, mucha densidad |
| 1.2 | tercera menor | conservadora, buena para interfaz |
| 1.25 | tercera mayor | el estándar de facto para contenido |
| 1.333 | cuarta justa | jerarquía marcada, buena para editorial |
| 1.5 | quinta justa | dramática, pocos pasos utilizables |
| 1.618 | sección áurea | muy abierta, títulos enormes |
Con base 16 y razón 1.25: 16, 20, 25, 31.25, 39.06. Con razón 1.2: 16, 19.2, 23.04, 27.65, 33.18.
El valor de una escala modular no es estético sino de sistema: elimina la decisión. No hay que discutir si el subtítulo mide 22 o 23; mide lo que le toca. Y como todos los tamaños comparten una relación, la jerarquía se percibe aunque el lector no sepa por qué.
Dos escalas, una por extremo
En una pantalla estrecha hay poco sitio, así que la diferencia entre el cuerpo y el titular tiene que ser moderada: si el titular es tres veces el cuerpo, ocupa cuatro renglones y no cabe nada más. En una pantalla ancha sobra sitio y la jerarquía puede abrirse.
Por eso la escala fluida bien construida usa una razón menor en el extremo estrecho y una mayor en el ancho:
- A 360 píxeles: base 16, razón 1.2.
- A 1240 píxeles: base 18, razón 1.25.
Y la tabla resultante, con los tamaños en píxeles:
| paso | a 360px | a 1240px |
|---|---|---|
| 0 | 16.00 | 18.00 |
| 1 | 19.20 | 22.50 |
| 2 | 23.04 | 28.13 |
| 3 | 27.65 | 35.16 |
| 4 | 33.18 | 43.95 |
Fíjate en lo que ha pasado: el cuerpo crece un 12.5% del extremo estrecho al ancho, y el paso 4 crece un 32%. La jerarquía se abre, que es el efecto que buscamos y que una escala con un único multiplicador global no puede producir.
Los cinco clamps
Aplicando a cada fila la derivación de la recta —B = 100(S2 − S1)/(V2 − V1) y A = (S1 − B·V1/100)/16— sale la escala completa:
:root {
--t-0: clamp(1rem, 0.949rem + 0.227vw, 1.125rem);
--t-1: clamp(1.2rem, 1.116rem + 0.375vw, 1.406rem);
--t-2: clamp(1.44rem, 1.310rem + 0.578vw, 1.758rem);
--t-3: clamp(1.728rem, 1.536rem + 0.853vw, 2.197rem);
--t-4: clamp(2.074rem, 1.798rem + 1.224vw, 2.747rem);
}
body { font-size: var(--t-0); }
h3 { font-size: var(--t-2); }
h2 { font-size: var(--t-3); }
h1 { font-size: var(--t-4); }
Comprobación del factor de respuesta en el peor punto, el extremo ancho:
paso 0 a 1240px: rem 15.18 + vw 2.82 = 18.00 -> f = 0.84
paso 4 a 1240px: rem 28.77 + vw 15.17 = 43.94 -> f = 0.65
Los dos por encima de 0.5, y no por casualidad: cuanto menor sea la diferencia entre los dos tamaños de un paso, menor es la pendiente y mayor el factor de respuesta. Una escala con dos razones cercanas es automáticamente más accesible que una con pendientes agresivas, lo cual es un argumento poco conocido a favor de la moderación.
Generarla en CSS con pow
Escribir cinco clamp() a mano funciona y es perfectamente legítimo. Pero pow() está en los tres motores desde hace tiempo —Safari 15.4, Firefox 118, Chrome 120— y permite expresar la escala como lo que es, sin números mágicos:
:root {
--v0: 360; --v1: 1240; /* anchos de referencia, sin unidad */
--s0: 16; --s1: 18; /* base en px en cada extremo */
--r0: 1.2; --r1: 1.25; /* razon en cada extremo */
}
.paso {
--min: calc(var(--s0) * pow(var(--r0), var(--n)));
--max: calc(var(--s1) * pow(var(--r1), var(--n)));
--b: calc(100 * (var(--max) - var(--min)) / (var(--v1) - var(--v0)));
--a: calc(var(--min) - var(--b) * var(--v0) / 100);
font-size: clamp(
calc(var(--min) / 16 * 1rem),
calc(var(--a) / 16 * 1rem + var(--b) * 1vw),
calc(var(--max) / 16 * 1rem)
);
}
h1 { --n: 4; }
h2 { --n: 3; }
h3 { --n: 2; }
Todo el cálculo intermedio se hace con números sin unidad y solo al final se multiplican por 1rem y por 1vw, que es lo que hace que el calc() sea válido. Cambiar la razón del extremo ancho de 1.25 a 1.333 es ahora un carácter, y toda la escala se recalcula.
La contrapartida honesta: estas custom properties se resuelven en cada elemento que las use, y el árbol de dependencias es más difícil de inspeccionar en las herramientas del navegador que cinco valores literales. En un sistema de diseño con generación en tiempo de construcción, calcular la tabla fuera y emitir los cinco clamp() finales suele ser preferible. La versión con pow() brilla cuando la escala tiene que poder cambiar en tiempo de ejecución, por ejemplo con un control de densidad en la interfaz.
Aquí hay una incoherencia matemática en el corazón de la técnica que conviene conocer aunque casi siempre sea inofensiva. Cada paso interpola linealmente entre su valor pequeño y su valor grande, pero los dos extremos son progresiones geométricas. La media aritmética de dos progresiones geométricas de razones distintas no es una progresión geométrica: en el punto medio del viewport, la razón entre pasos consecutivos ya no es constante. Y se puede medir. Con base 16 en los dos extremos y razones 1.2 y 1.25, las razones en el punto medio salen 1.2250, 1.2256, 1.2261 y 1.2265: una deriva del 0.1%, invisible. Con razones 1.125 y 1.5 salen 1.3125, 1.3393, 1.3650 y 1.3886: una deriva del 6% que sí se ve, porque significa que en los anchos intermedios los títulos grandes están relativamente más separados de lo que ninguna de tus dos escalas decía. La conclusión no es abandonar la técnica sino mantener las dos razones cerca, y entender que cuando las separas mucho estás inventando, en la franja intermedia, una escala que no has diseñado. La alternativa formalmente correcta —interpolar la razón y no los tamaños— existe y se puede escribir con pow(), pero exige un exponente que dependa del viewport y la ganancia solo justifica el esfuerzo cuando la deriva es visible.