Problem Solved

CSS · clamp()

Home › Courses › CSS › Problems › clamp()
🎨 Concept · 3 min read

Fluid text with clamp().
No media queries needed.

Font size that scales smoothly with the viewport, between a minimum and a maximum, with one line of CSS. That's clamp(). It replaces the media-query-based approach where you set a different size at every breakpoint. The heading is 2rem on mobile, 3.5rem on desktop, and something in between at every viewport width in between. This page covers the formula, the patterns for headings, and the accessibility rules that make it safe.

Short answer: Use font-size: clamp(min, preferred, max) for fluid text. The min and max should be in rem (never pure vw) to preserve accessibility. The preferred value is usually rem + vw: clamp(2rem, 1.5rem + 2.5vw, 3.5rem). Works for width, padding, margin too. Pick min for mobile, max for desktop, let the preferred value interpolate. This is the modern approach — no breakpoints, smooth scaling.

✅ How clamp() works

Three values. One result.

min

The floor. The value is never smaller than this. Use rem or em — never pure vw, or text gets too small.

preferred

The ideal value. Often a mix of rem and vw: 1.5rem + 2.5vw. This is what scales with the viewport.

max

The ceiling. The value is never larger than this. Use rem — prevents text from getting too big on ultrawide screens.

How it resolves

If preferred is within [min, max], use preferred. If preferred is below min, use min. If preferred is above max, use max.

✅ Before and after

Media queries vs clamp.

media-query-font.css
/* ❌ The old way — media queries /
h1 {
font-size: 2rem; / mobile */
}

@media (min-width: 768px) {
h1 { font-size: 2.5rem; } /* tablet */
}

@media (min-width: 1024px) {
h1 { font-size: 3rem; } /* desktop */
}

@media (min-width: 1280px) {
h1 { font-size: 3.5rem; } /* large desktop /
}
Result at every viewport width:

Viewport Font size
─────────────────────
320px 2rem (32px) ← min
400px 2rem (32px) ← min
600px 2.19rem (35px) ← scaling
768px 2.31rem (37px) ← scaling
1024px 2.81rem (45px) ← scaling
1280px 3.31rem (53px) ← scaling
1440px 3.5rem (56px) ← max
1920px 3.5rem (56px) ← max

✅ Smooth scaling at every viewport width.
✅ One declaration, no media queries.
✅ Min ensures text is never too small.
✅ Max ensures text is never too big.

The preferred value 1.5rem + 2.5vw:
1.5rem is a fixed baseline (24px at 16px root)
2.5vw scales with the viewport

Together they interpolate smoothly.
The rem keeps the scaling anchored to
the user's font size preferences.

✅ Better accessibility than pure vw.

✅ The formula

How to pick min, preferred, and max.

typography-scale.css
/* Body — subtle scaling */
body {
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
}

/* H2 — medium scaling */
h2 {
font-size: clamp(1.5rem, 1.25rem + 1.25vw, 2.5rem);
}

/* H1 — larger scaling */
h1 {
font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem);
}

/* Display — biggest, for hero sections */
.display {
font-size: clamp(2.5rem, 1.5rem + 5vw, 5rem);
}

/* Spacing also benefits */
.section {
padding-block: clamp(2rem, 5vw, 4rem);
}

/* Containers /
.container {
width: clamp(300px, 90vw, 1200px);
margin-inline: auto;
}
The pattern for every clamp():

clamp(min-rem, base-rem + scale-vw, max-rem)

How to pick the values:

1. Decide the mobile size (this is min).
2. Decide the desktop size (this is max).
3. The preferred value should reach min at
mobile and max at desktop.

Examples:

Body: 1rem mobile → 1.125rem desktop.
clamp(1rem, 0.95rem + 0.25vw, 1.125rem)
(subtle, almost imperceptible)

H2: 1.5rem mobile → 2.5rem desktop.
clamp(1.5rem, 1.25rem + 1.25vw, 2.5rem)

H1: 2rem mobile → 3.5rem desktop.
clamp(2rem, 1.5rem + 2.5vw, 3.5rem)

Rule of thumb: for every 1rem of growth from
mobile to desktop, add about 1vw to the
preferred value. This gives smooth scaling
without over- or under-shooting.

✅ Never use pure vw for font-size.
Always include a rem base.
Pure vw breaks user font-size preferences
and produces tiny text at small viewports.

Don't use pure vw in clamp() for font sizes. font-size: clamp(1rem, 3vw, 3rem) is fine — 3vw scales but the rem bounds protect it. But font-size: clamp(1vw, 3vw, 3rem) means the minimum is 1vw — on a 320px phone, that's 3.2px. The text is unreadable, and users who set their browser font size to 20px see no effect on the clamp. The rule: the min and max must be in rem or em, never vw. The preferred value can (and usually should) mix rem and vw. This preserves accessibility — user font-size preferences still work, and text is never too small.

⚠️ Common mistakes

The clamp() mistakes that cost real time.

1. Pure vw for min or max

clamp(1vw, 3vw, 3rem) — breaks accessibility. Fix: rem for min and max.

2. min > max

clamp(3rem, 2vw, 2rem) — invalid, clamps to min. Fix: min must be smaller than max.

3. Preferred value outside [min, max]

The clamp is a no-op. Fix: ensure the preferred value can reach both bounds.

4. Using clamp for very small text

Below ~14px, scaling loses value. Fix: use px or fixed rem for captions.

5. Clamp on line-height

Unitless line-height already scales. Fix: line-height: 1.5, not clamp.

6. Clamp on font-size without testing long words

Large fluid text overflows small containers. Fix: test with overflow-wrap: break-word.

7. Skipping min and max

clamp(1rem, 5vw) — only 2 values, invalid. Fix: 3 values, always.

8. Clamp everywhere

Fluid type on every element. Fix: use clamp for headings and body; keep captions, badges fixed.

❓ Frequently asked

How does CSS clamp() work?

clamp(min, preferred, max) returns the preferred value, constrained to the range [min, max]. font-size: clamp(1rem, 2.5vw, 2rem) means: at least 1rem, ideally 2.5% of the viewport width, at most 2rem. The preferred value is used whenever it falls within [min, max]. Below min → min. Above max → max.

What is the difference between clamp(), min(), and max()?

clamp(min, preferred, max) returns preferred, constrained to [min, max]. min(a, b) returns the smaller of a and b. max(a, b) returns the larger of a and b. So clamp(min, preferred, max) is equivalent to max(min, min(preferred, max)). For font sizes, clamp is almost always what you want — you specify the range explicitly.

What are good clamp values for headings?

For body text: clamp(1rem, 0.95rem + 0.25vw, 1.125rem). For h1: clamp(2rem, 1.5rem + 2.5vw, 3.5rem). For h2: clamp(1.5rem, 1.25rem + 1.25vw, 2.5rem). The pattern: pick the min size for mobile, the max for large desktop, and let the preferred value interpolate. The 'preferred' often uses a mix of rem and vw: 1.5rem + 2.5vw.

Does clamp() work for width, padding, and margin?

Yes — clamp() works on any property that accepts a length. Width: clamp(300px, 50vw, 800px). Padding: clamp(1rem, 3vw, 2rem). Margin: clamp(1rem, 5vw, 4rem). This is incredibly useful for container widths and spacing that should scale with the viewport.

Does clamp() hurt accessibility?

No — clamp() preserves user zoom and font-size preferences. The one risk: if you use vw for text, users who zoom by widening the viewport see text grow — this is fine. The critical rule: always include a min value in rem or em, never pure vw. clamp(1rem, 2vw, 2rem) preserves minimum size regardless of viewport.

When should I NOT use clamp() for font size?

Three cases. (1) When you need precise control over each breakpoint. (2) When the scaling would break the layout — fluid text that grows to 4rem on desktop may overflow a fixed-width card. (3) When the design is intentionally static — a small logo, a badge, a caption.

🔗 Related

← All CSS problems
Problem solved · CSS