Before clamp(), responsive typography meant stacking media queries. Set a size for mobile, another for tablet, another for desktop, and accept the jumps in between:
`css
h1 { font-size: 24px; }
@media (min-width: 768px) { h1 { font-size: 32px; } }
@media (min-width: 1200px) { h1 { font-size: 48px; } }
`
The font snaps at each breakpoint. Add more breakpoints, and the CSS multiplies.
clamp() collapses that into one line:
`css
h1 { font-size: clamp(1.5rem, 4vw, 3rem); }
`
The heading scales smoothly between 1.5rem and 3rem based on the viewport, with 4vw as the preferred size. No breakpoints, no jumps.
Use the Typography Scale Calculator to generate a full scale you can drop into your stylesheet, and the Font Converter when you need to switch between px, rem, and em while you build your clamp values.
How clamp() Syntax Works
clamp() takes three values:
`css
clamp(minimum, preferred, maximum)
`
Minimum: the floor. On small screens, the value never drops below this. Use rem so user font size settings still apply.
Preferred: a fluid value that follows the viewport, usually expressed in vw. This is what creates the scaling.
Maximum: the ceiling. On wide screens, the value stops growing here. Use rem again.
The browser picks the value by clamping the preferred result between the floor and the ceiling. That is mathematically the same as max(minimum, min(preferred, maximum)), just easier to read.
For the preferred value, mix vw with a rem base:
`css
font-size: clamp(1rem, 0.5rem + 2vw, 2rem);
`
The 0.5rem + 2vw slope starts from a real base size instead of zero. Without the rem portion, text shrinks dangerously on narrow viewports and stops scaling when users zoom in.

A Full Typography Scale with clamp()
A type scale that works from a 320px phone to a 1440px desktop:
`css
:root {
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.6vw, 1.25rem);
--text-xl: clamp(1.25rem, 1rem + 1.2vw, 1.5rem);
--text-2xl: clamp(1.5rem, 1.1rem + 1.8vw, 2rem);
--text-3xl: clamp(1.875rem, 1.2rem + 2.5vw, 2.5rem);
--text-4xl: clamp(2.25rem, 1.3rem + 3.5vw, 3.5rem);
}
h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
p { font-size: var(--text-base); }
small { font-size: var(--text-sm); }
`
CSS custom properties make the scale reusable. Change one variable and every heading and paragraph picks it up.
What this gives you:
- Body text never drops below 1rem (16px), so it stays readable.
- Headings scale with the viewport instead of jumping.
- The hierarchy between H1, H2, and H3 stays visible at every screen size.
Generate a matching scale and tune the ratio with the Typography Scale Calculator.
A type scale that works from a 320px phone to a 1440px desktop: ```css :root { --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem); --text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem); --text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem); --text-lg: clamp(1.125rem, 1rem + 0.6vw, 1.25rem); --text-xl: clamp(1.25rem, 1rem + 1.2vw, 1.5rem); --text-2xl: clamp(1.5rem, 1.1rem + 1.8vw, 2rem); --text-3xl: clamp(1.875rem, 1.2rem + 2.5vw, 2.5rem); --text-4xl: clamp(2.25rem, 1.3rem + 3.5vw, 3.5rem); } h1 { font-size: var(--text-4xl); } h2 { font-size: var(--text-3xl); } h3 { font-size: var(--text-2xl); } h4 { font-size: var(--text-xl); } p { font-size: var(--text-base); } small { font-size: var(--text-sm); } ``` CSS custom properties make the scale reusable.
clamp() for Spacing, Gaps, and Widths
clamp() works on any property that takes a length:
Padding and margins:
`css
.container { padding: clamp(1rem, 3vw, 4rem); }
`
Gap in flex and grid layouts:
`css
.card-grid { gap: clamp(1rem, 2vw, 2rem); }
`
Max-width for content containers:
`css
.content { max-width: clamp(300px, 80vw, 900px); }
`
Border radius:
`css
.card { border-radius: clamp(0.5rem, 1vw, 1.5rem); }
`
The payoff is proportions that feel intentional at every width. A card with 2rem of padding on desktop and 0.5rem on mobile reads as designed. The same card with a fixed 2rem on mobile burns half the screen.
Skip clamp() for things that should not scale at all: borders, hairline dividers, checkbox sizes, brand icons. Use it where proportional scaling pays off.
When you ship, run the output through the CSS Minifier so the extra clamp() calls do not pad your bundle.

Accessibility Rules for Fluid Typography
Fluid type has one big trap and a few smaller ones.
Browser zoom: users who zoom to 200% expect text to double. With pure vw, zooming does not change the viewport width, so the fluid portion does not scale. The fix is to keep a rem component in your preferred value.
Broken: clamp(1rem, 4vw, 2rem) (zoom only touches the min and max).
Fixed: clamp(1rem, 0.5rem + 2vw, 2rem) (the 0.5rem portion scales with zoom).
Minimum font size: WCAG does not set a hard number, but the safe floor for body text is 1rem (16px at default settings). Anything smaller fails older eyes on phones.
Text spacing: WCAG 1.4.12 requires text to stay readable when users adjust letter spacing, word spacing, and line height. Test that your layout does not collapse when those rules are applied.
Test plan: load the page at 200% zoom, then set the browser font size to "Very Large" in Chrome settings, then apply the WCAG text-spacing bookmarklet. If nothing overflows or clips, the implementation is good.
Fluid type has one big trap and a few smaller ones.
FAQ
Is clamp() supported in all browsers?
Yes. clamp() ships in every modern browser since 2020 (Chrome 79+, Firefox 75+, Safari 13.1+, Edge 79+). No polyfill needed in 2026.
Can I nest calc() inside clamp()?
Yes, but you usually do not need to. clamp() already evaluates math, so clamp(1rem, 0.5rem + 2vw, 3rem) works the same as clamp(1rem, calc(0.5rem + 2vw), 3rem).
How do I calculate the right vw value?
Pick two viewport widths and the size you want at each, then solve for the slope: (maxSize - minSize) / (maxViewport - minViewport) 100 = vw coefficient. To go from 1rem at 320px to 2rem at 1200px, the coefficient is (2 - 1) / (1200 - 320) 100 = 0.114, so the preferred value is 1rem + 0.114vw + extra base. A scale calculator does this for you.
Should I use clamp() or media queries?
Use both. clamp() handles smooth scaling of sizes (type, spacing, widths). Media queries handle layout changes (sidebar to stacked, hide/show, grid template swaps). They solve different problems and pair well together.
Markdown Table Generator: Build Clean Tables Without the Pain
Markdown tables are simple until the pipes and dashes stop lining up. Learn the syntax, alignment tricks, and a free tool that formats tables for you.
CSV to JSON: Convert Spreadsheet Data for APIs and Code
Turn a CSV export into clean JSON for APIs, imports, and scripts. Learn how the conversion works, common pitfalls with types and quotes, and a free tool.
JSON Guide: Format, Validate, and Convert JSON Files
JSON guide for developers: syntax rules, common parse errors, formatting and schema validation, plus how to convert between JSON and CSV files.
