Media-query typography means a hero is 48px on desktop, 36px on tablet, 28px on mobile - three rules, two jumps, and every tablet size in between gets a compromise. clamp() replaces all of it with one line.
The syntax
h1 { font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem); /* min 32px, fluid middle, max 56px */ } clamp(min, preferred, max). The middle value is what makes it work: 1.5rem + 2.5vw scales with the viewport but never below 32px or above 56px. Between breakpoints, EVERY viewport width gets an appropriate size - not just the three you wrote queries for.
Why the rem+vw combo matters
Pure 5vw scales infinitely: on a 4K monitor your hero is 190px. The Xrem + Yvw form sets the fluid slope (Yvw) and shifts where it starts (Xrem). The math for a target: if you want 32px at 375px viewport and 56px at 1440px:
slope = (56 - 32) / (1440 - 375) = 0.0225 → 2.25vw intercept = 32 - 2.25 * 375 / 100 = 23.6 → use rem for it font-size: clamp(2rem, 1.475rem + 2.25vw, 3.5rem); (min = max = the 32/56 targets; the fluid middle hits both exactly.)
The accessibility check that most implementations fail
vw-based sizes ignore user font-size preferences. If a user sets their browser default to 24px, vw sizes stay fixed. The fix: keep the rem component meaningful and cap the max at a size that respects the user's base (calc() with rem keeps preference-awareness). Utopia.fyi's fluid calculator bakes this in - use it instead of hand-rolling the math.
The debugging reality
Fluid type changes size at every scroll-resize, which means layout bugs surface at odd viewport widths nobody tested. The classic one: the font renders differently than the token says because a fallback substituted somewhere in the stack. Screenshot at the broken width and identify what actually rendered - Typeye names the typeface from the screenshot, entirely on-device.
Fluid type is the rare technique that is BOTH less code and better results. Convert one heading scale and the rest follows.
