Tutorial · html-css-js · Published 2026-08-16 · 3 min read
clamp() for fluid typography
Understand clamp() fluid typography: the clamp() syntax, viewport units, safe fallbacks, and the no-unit-on-bounds trap.
The feature in one line
clamp(min, preferred, max) returns the preferred value when that value sits between the min and max, the min when preferred is lower, and the max when preferred is higher. Because the preferred argument can include a viewport unit, type can scale continuously with the viewport instead of jumping at hard breakpoints.
h1 { font-size: clamp(1.6rem, 1rem + 3vw, 3rem); }
The article em vs rem covers why the base unit here is rem: clamp() does not remove the need for a sensible base, it makes the size a function of the viewport around that base.
The math and the trap
The common form clamp(1.6rem, 1rem + 3vw, 3rem) is two terms: a fixed value and a vw slope. The slope is what makes it fluid. The trap is that the two boundary values must be different, and the browser resolves the whole expression with real unit conversion. Two common bugs:
- Flat preferred.
clamp(1.6rem, 1rem, 3rem)always returns1rem, because the min is above the preferred; the jumbo size never appears. Check the browser DevTools computed size to see which argument actually wins. - No unit on the bounds.
clamp(16, 1rem + 3vw, 48)is invalid: the two bounds need units. In CSS you must writeclamp(1rem, 1rem + 3vw, 3rem)with units on both min and max, else the whole declaration is invalid and the property falls back to an earlier rule. - Calc is optional.
clamp(1rem, 3vw, 3rem)is valid: a barevwis a valid preferred. Use the calc form only when you need a fixed offset at small sizes.
A common safe pattern for body text is a sub-logarithmic slope so it does not balloon on a phone:
body { font-size: clamp(1rem, 0.9rem + 0.5vw, 1.15rem); }
When clamp wins over a breakpoint
Clamp is not a replacement for every media query; it is the right tool when the change is a smooth ramp. These three cases fit it best:
- Headings and display text that should stress the viewport width with no width-jump between breakpoints.
- Line-height and spacing pairs that track the same ramp. Use the same
clamp()value for margins and padding when the design wants the space to scale with the text. - Component font that must not undercut accessibility (a footer caption cannot fall below
0.875remregardless of the viewport: put that as the min).
Do not use clamp for layout that has real breakpoints in the design: flexbox/grid columns, and a nav that switches to a drawer, still belong in a media query. See responsive breakpoints for where the media query is the honest tool.
Fallback behaviour
Older browsers reject clamp() as an unknown function and drop the whole declaration. Always write a static fallback line before the clamp:
h2 {
font-size: 2.2rem; /* fallback */
font-size: clamp(1.8rem, 1rem + 4vw, 3rem);
}
The fallback also keeps your invariance if any unit in the expression is unsupported. DevTools Minimum font size and zooming still compose with clamp, provided you keep min at a real text size and never let the min fall below the browser's accessible floor.
The em vs rem article builds the base units article, and responsive breakpoints keeps media queries in the places clamp cannot reach.