CSS clamp() Explained: Truly Responsive Typography

September 26, 2026 · Design

Responsive typography used to mean a stack of media queries: 16px on phones, 18px on tablets, 20px on desktops, with jarring jumps between. CSS clamp() replaces all of that with a single declaration — type that scales smoothly with the viewport, never smaller than your minimum, never larger than your maximum. Here's how it works, the math behind it, and the one accessibility rule everyone forgets.

What clamp() does: minimum, preferred, maximum

The syntax is clamp(MIN, PREFERRED, MAX):

  • MIN — the floor. The value never goes below this.
  • PREFERRED — the ideal value, usually fluid (viewport-relative).
  • MAX — the ceiling. The value never exceeds this.

It's shorthand for max(MIN, min(PREFERRED, MAX)). The browser computes the preferred value, then clamps it into range. If you can read "at least X, ideally Y, at most Z", you can read clamp().

Reading the syntax with a worked example

Take font-size: clamp(1rem, 0.9rem + 1vw, 1.5rem):

  • On a 320px-wide phone: 1vw = 3.2px, so preferred = 14.4px + 3.2px = 17.6px. Within range → 17.6px.
  • On a 768px tablet: preferred = 14.4px + 7.68px = 22.08px → 22.08px.
  • On a 1920px monitor: preferred = 14.4px + 19.2px = 33.6px, but MAX is 24px (1.5rem) → 24px.

No breakpoints, no jumps — every intermediate width gets an intermediate size. That's the whole magic: one line, infinite steps.

Fluid typography: the headline use case

Fluid type means headings that grow with the screen instead of snapping between fixed sizes. A typical scale:

h1 { font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem); }
h2 { font-size: clamp(1.4rem, 1.1rem + 1.5vw, 2rem); }
p  { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem); }

Notice body text gets a tiny vw component — paragraphs shouldn't swing wildly; headings carry the drama. A common mistake is making everything equally fluid, which makes small screens feel cramped and large screens feel shouty. Scale the range with the element's importance.

Deriving the preferred value: the math, step by step

The preferred value is a straight line between two points you choose. Say you want 16px at a 320px viewport and 24px at 1280px:

  1. Slope = (24 − 16) / (1280 − 320) = 8 / 960 = 0.00833 px per px of viewport = 0.833vw.
  2. Intercept = 16 − (0.00833 × 320) = 16 − 2.67 = 13.33px = 0.833rem (at a 16px root).
  3. Result: clamp(1rem, 0.833rem + 0.833vw, 1.5rem).

Check it: at 320px → 13.33 + 2.67 = 16px ✓; at 1280px → 13.33 + 10.67 = 24px ✓. The vw term is the slope (how fast it grows), the rem term is the intercept (where the line would hit a zero-width viewport). You don't need to do this by hand every time — that's what calculators are for.

Skip the arithmetic: enter your min/max sizes and viewport range in our free CSS Clamp Calculator and get the exact clamp() expression.

The accessibility rule: always include a rem term

You'll see clamp(1rem, 2.5vw, 2rem)-style snippets with a pure-vw preferred value. Don't copy them. A pure viewport unit ignores the user's font-size preference and — critically — breaks browser zoom: zooming a page with font-size: 2.5vw text doesn't enlarge the text as expected, because vw tracks the viewport, not the zoom level. That fails WCAG 1.4.4 (Resize Text), which requires text to scale up to 200% without loss of content.

The fix costs nothing: make the preferred value Xrem + Yvw. The rem term anchors a floor to the user's settings; the vw term adds fluidity on top. Every example in this article follows this pattern — treat a bare vw preferred value as a code smell.

Beyond fonts: fluid spacing and widths

clamp() accepts any length, so the same technique fluidizes layout:

/* Section padding that breathes with the screen */
section { padding: clamp(2rem, 5vw, 5rem); }

/* Card gaps */
.grid { gap: clamp(1rem, 2.5vw, 2rem); }

/* Container that's fluid but never silly */
.container { width: clamp(20rem, 90vw, 70rem); }

Fluid spacing keeps vertical rhythm proportional: generous on desktop, compact on mobile, with no breakpoint maintenance. It's one of the highest-leverage single declarations in responsive CSS.

clamp() vs media queries vs min()/max()

  • Use clamp() for continuous values: font sizes, spacing, widths that should glide between bounds.
  • Use min()/max() for one-sided constraints: width: min(100%, 60rem) (never wider than 60rem) is clearer than a clamp with a dummy bound.
  • Use media queries for discrete changes: rearranging grid columns, swapping navigation patterns, hiding elements. Breakpoints are for structure, not sizing.

The modern responsive toolkit is all three: clamp() handles the smooth stuff, media queries handle the structural stuff, and your CSS gets dramatically shorter than the breakpoint-soup era.

Frequently asked questions

What does clamp() do in CSS?
It constrains a value between a minimum and a maximum: clamp(MIN, PREFERRED, MAX). The browser uses the preferred value, but never lets it go below MIN or above MAX. The classic use is fluid typography that scales with viewport width yet stays within readable bounds.
How do you calculate the preferred value?
Pick the size you want at a small viewport and at a large viewport, then solve the line between them: slope = (maxSize − minSize) / (maxWidth − minWidth), expressed in vw units, plus an intercept in rem. Our calculator does this arithmetic for you — the worked example in the article shows each step.
Is clamp() supported in all browsers?
Yes, effectively. clamp() (along with min() and max()) reached Baseline support in 2022 and works in all modern browsers — Chrome/Edge, Firefox, and Safari. No fallback is needed for any audience on current browsers.
Does clamp() replace media queries?
For smooth scaling it does — fluid type needs no breakpoints. But media queries still own discrete layout changes (rearranging grids, hiding elements, switching navigation). Use clamp() for continuous values, media queries for structural shifts.
Why add rem to the preferred value?
A pure-vw preferred value (like 2.5vw) ignores the user's font-size settings and breaks browser zoom, failing WCAG 1.4.4 (resize text). Adding a rem term (e.g. 1rem + 2vw) keeps a floor tied to the user's preferred size, so text still scales when they zoom.
Can I use clamp() for padding and margins?
Absolutely — clamp() works anywhere a length is accepted: padding, gap, border-radius, even container max-widths. Fluid spacing (e.g. padding: clamp(1rem, 4vw, 3rem)) keeps rhythm proportional across screen sizes with one declaration.
What's the difference between clamp(), min(), and max()?
min() picks the smallest of its arguments (a ceiling), max() picks the largest (a floor), and clamp(MIN, VAL, MAX) is equivalent to max(MIN, min(VAL, MAX)) — a value with both a floor and a ceiling. clamp() is the one you want for fluid values with guardrails.

Related articles

Try the free tool