How it works
clamp() takes three values and returns the middle one:
font-size: clamp(1rem, 0.8333rem + 0.8333vw, 1.5rem);The first is the lower limit, the last is the upper limit, and the one in between is the preferred value. Because the preferred value contains vw, it grows with the screen until it hits a limit. That replaces a stack of breakpoints with one line.
Where the numbers come from
You want a straight line through two points: 16px on a 320px screen and 24px on a 1280px screen.
- Slope: how much the size changes per pixel of width.
(24 - 16) / (1280 - 320) = 0.008333. - Viewport part:
1vwis 1% of the width, so multiply by 100.0.8333vw. - Fixed part: the size the line would have at zero width.
16 - 0.008333 × 320 = 13.333px, which is0.8333remwith a 16px root.
Check it on an 800px screen: 13.333 + 0.008333 × 800 = 20px, exactly halfway between 16 and 24.
Fluid type and zoom
Browser zoom makes a CSS pixel bigger, which means fewer CSS pixels fit across the window. Anything in vw stays the same size on screen, while rem scales with the zoom. So the larger the vw share of a font size, the less that text responds to zoom.
WCAG 1.4.4 asks that text can be resized to 200%. A common rule of thumb is to keep the largest size within 2.5 times the smallest, and the calculator warns you when a font size goes past that. Test big headings at 200% zoom anyway.
Keep the limits in rem too. A font size written in px ignores the default font size people choose in their browser settings.
Common mistakes
- A bare zero.
clamp(0, 1vw, 1rem)is invalid, because0here is a number and not a length. Write0rem. - Missing spaces.
+and-need a space on both sides inside math functions.1rem+1vwis invalid. Tailwind classes can't contain spaces, so the Tailwind output here writes them as underscores. - Viewport width isn't component width. A sidebar card doesn't care how wide the window is. For size relative to a container, swap
vwforcqiand setcontainer-type: inline-sizeon the parent. The min and max viewport fields then mean container widths.
Where it works well
Headings, section padding and grid gaps benefit the most, since they have the widest range between phone and desktop. Body text barely needs it: 16px to 18px is about all the range it should have.