Fluid Typography with CSS clamp(): No More Font-Size Breakpoints
Responsive type used to mean writing the same font-size rule four times, once per breakpoint, and accepting that it jumped between them. The clamp() function replaces the whole arrangement with a single value that scales smoothly, and the CSS clamp() Calculator works out the middle part for you.
What clamp() takes
Three values: a minimum, a preferred value, and a maximum. The browser uses the preferred value unless it falls outside the other two, in which case it uses whichever bound it hit.
The minimum and maximum are straightforward - the smallest and largest you ever want the text. The preferred value is where it gets fiddly, because to scale with the viewport it needs a viewport unit, and to scale at the right rate it needs a fixed offset alongside it. Something like 1rem plus 2vw. Getting that pair right by hand is algebra, which is precisely why a calculator exists.
Why smooth beats stepped
With breakpoints, a heading is one size at 767px and noticeably different at 768px. Nobody resizes a browser while reading, so the jump is rarely seen - but the sizes between breakpoints are compromises, chosen for a range rather than a width. Fluid type is correct at every width instead of at four of them.
It also collapses a lot of CSS. One line instead of a rule repeated through several media queries, for every element whose size should respond.
The limits worth knowing
Set a minimum you would genuinely accept on the narrowest phone - fluid type will happily shrink text past readable if you let it. And cap the maximum, or headings become absurd on a wide monitor.
Zooming is the other consideration. Sizes based purely on viewport units do not respond to a reader zooming in, which some people rely on. Keeping a rem-based component in the preferred value, as the calculator does, avoids that.
How to use it
Open the tool, enter your minimum and maximum sizes and the viewport range you want the scaling to happen across, and copy the resulting clamp() value.
Scaling a whole type system, not one heading
Applying clamp() to a single heading works and misses most of the benefit. What you usually want is for the relationships between sizes to hold as the screen changes - a heading staying proportionally larger than the body text at every width.
The practical approach is to make the body size fluid and define everything else relative to it in rem. Headings, spacing and component sizes then scale together from one value, and you have one thing to tune rather than a dozen.
Watch the rate of change. Text that grows too quickly with the viewport looks unstable when a window is resized; a gentle slope between a sensible minimum and maximum reads as intentional.
Common questions
Does clamp() work everywhere?
It is supported across all current browsers and has been for several years.
Can I use it for spacing too?
Yes - padding, margins and gaps all take it, and fluid spacing pairs naturally with fluid type.
Can I use clamp() for widths as well?
Yes, and it is a neat way to set a container that grows with the screen but never exceeds a comfortable reading measure.
What happens below the minimum viewport width?
Nothing breaks - the value simply stays at the minimum you set.
Work out your values: