Funciones de tamaño
Lección 19 de 37 · 4 min
Con unidades fijas, un tamaño vale lo mismo en un teléfono y en un monitor. Las funciones de CSS hacen la cuenta en el navegador, así que un mismo valor se adapta solo al lugar que hay.
calc(), min() y max()
calc() hace cuentas mezclando unidades, algo que no podés resolver de antemano: calc(100% - 2rem) es todo el ancho menos 32px, sea cual sea ese ancho. El + y el - necesitan un espacio a cada lado; sin ellos, 100%-2rem se lee como un número negativo pegado y el navegador descarta la declaración. El * y la / no los necesitan.
min() devuelve el menor de sus valores y max() el mayor. En la práctica funcionan como techo y piso: min(100%, 30rem) nunca pasa de 30rem, y max(1rem, 5vw) nunca baja de 1rem. Adentro aceptan cuentas sin escribir calc().
.caja {width: calc(100% - 2rem); /* todo el ancho menos 32px */width: min(100%, 30rem); /* el 100%, pero nunca más de 480px */padding-inline: max(1rem, 5vw); /* el 5vw, pero nunca menos de 16px */}
Mové el ancho del viewport y mirá qué valor gana en cada función. El título usa clamp(), que combina las dos; subí el mínimo para verlo ganar en pantallas chicas.
- padding-inline
- max(1rem, 5vw) 40px
- width
- min(100%, 30rem) 480px
- font-size
- clamp(1rem, 0.75rem + 1.5vw, 2rem) 24px
.pagina {padding-inline: max(1rem, 5vw); /* = 40px */}.articulo {width: min(100%, 30rem); /* = 480px */margin-inline: auto;}.titulo {font-size: clamp(1rem, 0.75rem + 1.5vw, 2rem); /* = 24px */}
<main class="px-[max(1rem,5vw)]"><article class="mx-auto w-[min(100%,30rem)]"><h1 class="text-[clamp(1rem,0.75rem+1.5vw,2rem)]">Una semana en Banff</h1></article></main>
clamp() y tipografía fluida
clamp(mínimo, preferido, máximo) devuelve el valor preferido mientras quede entre los dos límites. Es lo mismo que max(mínimo, min(preferido, máximo)), así que si el mínimo es mayor que el máximo, gana el mínimo.
Para tipografía fluida, el preferido crece con el viewport. Armalo como rem + vw y no solo con vw: el zoom no cambia cuánto mide 1vw en la pantalla, así que un título en 5vw no se agranda y puede fallar el criterio 1.4.4 de WCAG, que pide poder ampliar el texto al 200%. La parte en rem sí sigue al zoom y al tamaño de letra que elige quien lee. Igual probalo: si el vw pesa mucho, puede no llegar al doble.
Para sacar los números, partí de dos puntos: 18px en un viewport de 320px y 36px en uno de 1280px.
- Pendiente
1.875vw(36 - 18) / (1280 - 320) = 0.01875. Por 100 da1.875vw. - Ordenada al origen
0.75rem18 - 0.01875 × 320 = 12px, o sea0.75rem. - Límites
1.125rem · 2.25rem18px y 36px, pasados a rem.
h1 {/* 18px con 320px de viewport, 36px con 1280px */font-size: clamp(1.125rem, 0.75rem + 1.875vw, 2.25rem);}
Más allá del texto
Las mismas funciones sirven para cualquier longitud:
- Relleno
padding-inline: max(1rem, 5vw)Deja 16px en un teléfono y el 5% del viewport a partir de 320px de ancho. - Ancho de lectura
width: min(100%, 40rem)Ocupa todo en pantallas chicas y se frena en 640px, sin unmax-widthaparte. - Componentes
clamp(1rem, 0.5rem + 4cqi, 1.5rem)Concqien vez devwsigue al ancho del contenedor y no al de la pantalla. Lo vimos en container queries.
También existen round(), que redondea a un múltiplo (round(nearest, 37px, 8px) da 40px), y mod(), que devuelve el resto de una división. Son recientes: funcionan en todos los navegadores principales recién desde 2024, así que poné antes una declaración sin la función como respaldo.
En Tailwind
Tailwind no tiene utilidades para estas funciones: van como valores arbitrarios, entre corchetes. Una clase no puede tener espacios, así que se escriben sin ellos y Tailwind los vuelve a poner alrededor del + y el - al compilar.
| CSS | Tailwind |
|---|---|
| font-size: clamp(1rem, 0.75rem + 1.5vw, 2rem) | text-[clamp(1rem,0.75rem+1.5vw,2rem)] |
| width: min(100%, 30rem) | w-[min(100%,30rem)] |
| padding-inline: max(1rem, 5vw) | px-[max(1rem,5vw)] |
| width: calc(100% - 2rem) | w-[calc(100%-2rem)] |
<!-- relleno fluido y una columna de lectura centrada --><main class="px-[max(1rem,5vw)]"><article class="mx-auto w-[min(100%,40rem)]"><h1 class="text-[clamp(1.125rem,0.75rem+1.875vw,2.25rem)]">…</h1></article></main><!-- un título que sigue a su contenedor --><div class="@container"><h2 class="text-[clamp(1rem,0.5rem+4cqi,1.5rem)]">…</h2></div>
Sizing functions
Lesson 19 of 37 · 4 min
With fixed units, a size is the same on a phone and on a monitor. CSS functions do the math in the browser, so one value adapts on its own to the room there is.
calc(), min() and max()
calc() does math with mixed units, something you can't work out ahead of time: calc(100% - 2rem) is the full width minus 32px, whatever that width is. + and - need a space on each side; without them, 100%-2rem reads as a negative number stuck to the first one and the browser drops the declaration. * and / don't need them.
min() returns the smallest of its values and max() the largest. In practice they work as a ceiling and a floor: min(100%, 30rem) never goes past 30rem, and max(1rem, 5vw) never drops below 1rem. They take math inside without writing calc().
.box {width: calc(100% - 2rem); /* the full width minus 32px */width: min(100%, 30rem); /* 100%, but never more than 480px */padding-inline: max(1rem, 5vw); /* 5vw, but never less than 16px */}
Move the viewport width and watch which value wins in each function. The heading uses clamp(), which combines both; raise the minimum to see it win on small screens.
- padding-inline
- max(1rem, 5vw) 40px
- width
- min(100%, 30rem) 480px
- font-size
- clamp(1rem, 0.75rem + 1.5vw, 2rem) 24px
.page {padding-inline: max(1rem, 5vw); /* = 40px */}.article {width: min(100%, 30rem); /* = 480px */margin-inline: auto;}.title {font-size: clamp(1rem, 0.75rem + 1.5vw, 2rem); /* = 24px */}
<main class="px-[max(1rem,5vw)]"><article class="mx-auto w-[min(100%,30rem)]"><h1 class="text-[clamp(1rem,0.75rem+1.5vw,2rem)]">A week in Banff</h1></article></main>
clamp() and fluid type
clamp(minimum, preferred, maximum) returns the preferred value as long as it stays between both limits. It's the same as max(minimum, min(preferred, maximum)), so if the minimum is larger than the maximum, the minimum wins.
For fluid type, the preferred value grows with the viewport. Build it as rem + vw, not vw alone: zoom doesn't change how big 1vw is on screen, so a heading in 5vw doesn't grow and can fail WCAG criterion 1.4.4, which asks that text can be resized to 200%. The rem part does follow zoom and the font size the reader picks. Test it anyway: if the vw part weighs too much, it may not reach double.
To get the numbers, start from two points: 18px at a 320px viewport and 36px at a 1280px one.
- Slope
1.875vw(36 - 18) / (1280 - 320) = 0.01875. Times 100 gives1.875vw. - Intercept
0.75rem18 - 0.01875 × 320 = 12px, which is0.75rem. - Limits
1.125rem · 2.25rem18px and 36px, in rem.
h1 {/* 18px at a 320px viewport, 36px at 1280px */font-size: clamp(1.125rem, 0.75rem + 1.875vw, 2.25rem);}
Beyond text
The same functions work for any length:
- Padding
padding-inline: max(1rem, 5vw)Leaves 16px on a phone and 5% of the viewport from 320px wide up. - Reading width
width: min(100%, 40rem)Takes the full width on small screens and stops at 640px, with no separatemax-width. - Components
clamp(1rem, 0.5rem + 4cqi, 1.5rem)Withcqiinstead ofvwit follows the container's width, not the screen's. We saw it in container queries.
There are also round(), which rounds to a multiple (round(nearest, 37px, 8px) gives 40px), and mod(), which returns the remainder of a division. They're recent: they only work in every major browser since 2024, so put a declaration without the function before them as a fallback.
In Tailwind
Tailwind has no utilities for these functions: they go in as arbitrary values, in brackets. A class can't hold spaces, so you write them without any and Tailwind puts them back around + and - when it compiles.
| CSS | Tailwind |
|---|---|
| font-size: clamp(1rem, 0.75rem + 1.5vw, 2rem) | text-[clamp(1rem,0.75rem+1.5vw,2rem)] |
| width: min(100%, 30rem) | w-[min(100%,30rem)] |
| padding-inline: max(1rem, 5vw) | px-[max(1rem,5vw)] |
| width: calc(100% - 2rem) | w-[calc(100%-2rem)] |
<!-- fluid padding and a centered reading column --><main class="px-[max(1rem,5vw)]"><article class="mx-auto w-[min(100%,40rem)]"><h1 class="text-[clamp(1.125rem,0.75rem+1.875vw,2.25rem)]">…</h1></article></main><!-- a heading that follows its container --><div class="@container"><h2 class="text-[clamp(1rem,0.5rem+4cqi,1.5rem)]">…</h2></div>
