Fluid Typography with clamp
Use clamp(min, preferred, max) for fluid type and spacing — viewport units, the linear equation pattern, and accessibility floors.
- css
- clamp
- typography
Fluid type scales continuously between a minimum and maximum so you drop a handful of font-size media queries. clamp(MIN, VAL, MAX) is the primitive: never smaller than MIN, never larger than MAX, prefer VAL in between.
Docs: MDN clamp(), CSS values, fluid type techniques.
The pattern
:root {
--step-0: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--step-1: clamp(1.25rem, 1.1rem + 0.75vw, 1.75rem);
--step-2: clamp(1.5rem, 1.2rem + 1.5vw, 2.5rem);
}
body {
font-size: var(--step-0);
line-height: 1.5;
}
h1 {
font-size: var(--step-2);
line-height: 1.15;
}
VAL is often a linear mix of rem + vw so type grows with the viewport but stays anchored to root font size (user zoom / browser defaults still matter).
Why not raw vw alone?
/* Risky */
h1 {
font-size: 5vw;
}
Pure vw can become unreadably small on narrow screens and huge on ultra-wide ones, and it can ignore user font-size preferences more harshly depending on setup. clamp enforces floors and ceilings; including rem in the middle term respects root sizing better than pure viewport units.
Computing the middle term
You want size A at viewport width Vmin and size B at Vmax. The line:
[ font-size = slope \times 100vw + intercept ]
Many teams use a generator (Utopia, open-type-tools) or a small calc:
/* Example hand-tuned */
h1 {
font-size: clamp(1.75rem, 1rem + 2.5vw, 3rem);
}
Test at 320px, 768px, 1280px, 1600px — not only the happy laptop width.
Fluid spacing too
.section {
padding-block: clamp(2rem, 1.5rem + 3vw, 5rem);
padding-inline: clamp(1rem, 0.5rem + 2vw, 2.5rem);
gap: clamp(0.75rem, 0.5rem + 1vw, 1.5rem);
}
Keep vertical rhythm related to type steps so headings don’t float in arbitrary space.
Container-relative fluid type
When the component lives in a sidebar, viewport-based type can feel wrong. Prefer container query units:
.card {
container-type: inline-size;
}
.card__title {
font-size: clamp(1rem, 2.5cqi + 0.75rem, 1.5rem);
}
Accessibility floors
- Minimum body text: commonly ≥ 1rem (16px) unless the product has a strong reason and tested zoom.
- Don’t disable zoom (
user-scalable=no). - Check line length: fluid type on full-bleed containers can produce 120+ character lines — constrain
max-inline-size(e.g.70ch).
.prose {
font-size: var(--step-0);
max-inline-size: 65ch;
}
Interview out-loud
“clamp(min, preferred, max) caps a fluid value. For type I use a rem-based minimum, a rem+vw preferred middle, and a rem maximum so text scales with the viewport without becoming unusable. I also clamp spacing and often prefer container units for component-local type. Media queries still handle font family or major layout shifts.”
Footguns
clampwith incompatible units that don’t compute.- Only testing desktop widths.
- Fluid headings without max measure → awkward wraps.
- Nested clamps that nobody can reason about — name tokens.
- Assuming clamp replaces all typography design — line-height and weight still matter.
Type scale example
:root {
--fs-sm: clamp(0.875rem, 0.85rem + 0.15vw, 0.95rem);
--fs-md: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--fs-lg: clamp(1.25rem, 1.1rem + 0.75vw, 1.75rem);
--fs-xl: clamp(1.75rem, 1.3rem + 1.8vw, 3rem);
--lh-tight: 1.2;
--lh-body: 1.55;
}
body { font-size: var(--fs-md); line-height: var(--lh-body); }
h1 { font-size: var(--fs-xl); line-height: var(--lh-tight); }
h2 { font-size: var(--fs-lg); line-height: var(--lh-tight); }
small, .meta { font-size: var(--fs-sm); }
Lock the scale early; fluid type without a scale becomes one-off clamps nobody trusts. Pair with a max measure on prose containers so large desktops do not produce 120-character lines.
Related
Further reading
Related guides
- Accent Color and Form ControlsUse accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.
- BEM Naming MethodologyBlock, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.
- blend-mode Basicsmix-blend-mode vs background-blend-mode — how pixels combine, isolation, and the stacking/readability traps in product UI.
- box-sizing border-boxWhy border-box makes width include padding and border, the global reset pattern, and the layout bugs content-box still causes.