clamp(), with the line shown
The preferred value is the straight line through your two points — both endpoints asserted, and the samples showing where it clamps.
clamp(), with the line shown
The preferred value is the straight line through your two points. Both endpoints are asserted exactly, and the samples show where it clamps.
The derivation
What it produces at each width
The formula
slope = (yMax − yMin) / (xMax − xMin), intercept = yMin − slope × xMin, and the preferred value is intercept + slope×100vw. clamp() then holds it flat outside the range.
The intercept is emitted in rem by default. A preferred value made only of vw does not respond to the browser's font-size setting at all, so text sized that way cannot be enlarged by a reader who needs it larger. Keeping a rem term is what makes this safe on type.
Both endpoints are checked: the line is asserted to pass through exactly your minimum at the small viewport and exactly your maximum at the large one.
Why not just use media queries?
Breakpoints make type jump. A heading that is 32px at 767px and 44px at 768px is a visible step, and there are always widths in between that neither size suits.
A clamp gives every width its own size, and it is one declaration instead of three.
It works for anything, not just type
Padding, gaps, container widths, border radii, even a shadow's blur. Anywhere a value should move smoothly between two viewport widths, the same line applies.
For a font size specifically, keep the output in rem — the fluid type page explains why.