Menu

CSS clamp(): Fluid Font Sizes, min() and max()

clamp(MIN, PREFERRED, MAX) returns the preferred value but never less than MIN or more than MAX. Learn how it makes font sizes and spacing fluid without media queries, how to calculate the middle value, and how min() and max() relate to it.

This page includes runnable editors - edit, run, and see output instantly.

What clamp() does

clamp(MIN, PREFERRED, MAX) takes three values and returns the middle one, as long as it stays between the other two. The classic use is a heading that grows with the screen but stops at sensible limits, with no media query:

The preferred value is 1rem + 3vw: 16px plus 3% of the width. In a preview 800px wide that is 16 + 24 = 40px, which is between 24px (1.5rem) and 48px (3rem), so the heading is 40px. On a 320px phone the preferred value is 25.6px. Past 1067px it would exceed 48px, so it stops at 48px. Resize the window to watch the number change; vw here is a percentage of the preview frame's width.

See it without resizing the window

vw follows the viewport, which you cannot easily change while reading. Container query units follow a container instead: cqi is 1% of the container's width. Drag the slider to change the box, and the same kind of clamp() responds:

Slide to the start and the title stops at 20px (the MIN). Slide to the end and it stops at 40px (the MAX). In between it follows 0.5rem + 6cqi. This is the same mechanism as the vw version, with a smaller ruler.

The three arguments

font-size: clamp(1rem, 0.8rem + 1vw, 1.5rem);
/*               MIN   PREFERRED     MAX    */
ArgumentRoleTypical unit
MINthe smallest the value may getrem
PREFERREDthe value that changes with the screenrem + vw (or cqi)
MAXthe largest the value may getrem

Math works inside each argument without writing calc(): 1rem + 2vw is fine as it is. The + and - need a space on both sides, or the whole declaration is invalid.

If MIN is larger than MAX, MIN wins: clamp(3rem, 5vw, 2rem) is always 3rem.

Calculating the middle value

To grow a font from 16px on a 320px screen to 24px on a 1280px screen:

  1. Slope: (24 − 16) ÷ (1280 − 320) = 8 ÷ 960 = 0.00833, which is 0.833vw (vw is per 100px).
  2. Starting point: 16px − 0.00833 × 320px = 13.33px, which is 0.833rem.
  3. Put the limits around it:
font-size: clamp(1rem, 0.833rem + 0.833vw, 1.5rem);

At 320px wide this gives 13.33 + 2.67 = 16px, at 1280px it gives 13.33 + 10.67 = 24px, and outside that range it stays at the limits. Online "clamp calculators" do exactly this arithmetic.

min() and max()

clamp() is a combination of two simpler functions:

  • min(a, b) returns the smaller value, so it sets an upper limit.
  • max(a, b) returns the larger value, so it sets a lower limit.
  • clamp(MIN, VAL, MAX) is the same as max(MIN, min(VAL, MAX)).

The names feel backwards at first: to say "at most 600px", you use min().

In the wide preview the first card stops at 420px. Inside the 260px parent, 100% is the smaller value, so the second card is 260px. max(12px, 3%) gives the first card 3% of its parent's width (the body: about 23.5px in an 800px preview), and the second 12px, because 3% of 260px (7.8px) is below the floor.

width: min(100%, 420px) replaces the older pair width: 100%; max-width: 420px; in a single declaration.

Beyond font sizes: spacing and widths

clamp() works in any property that takes a length. Percentages in the middle value make a component fluid relative to its parent instead of the viewport:

In the 300px parent the card is 240px wide (80%) with 15px of padding (5% of 300px). In the 760px parent 80% would be 608px, so the card stops at its 520px maximum, and 5% of 760px is 38px, so the padding stops at 32px.

Accessibility: keep rem in the middle value

A font size made only of vw, like font-size: 5vw, does not grow when the reader raises the default font size in the browser settings, and it does not grow with browser zoom either, because zooming makes the viewport narrower in CSS pixels. Adding a rem part (1rem + 2vw) and rem limits keeps the text tied to the reader's setting. The units page explains rem and vw in detail.

Common mistakes

  • Using min() for a minimum. min() picks the smaller value, which is an upper limit. For "at least 12px", use max(12px, ...).
  • No spaces around + or -. clamp(1rem, 1rem+2vw, 3rem) is invalid, and the property falls back to its previous value.
  • Only vw in the middle. The text then ignores the reader's font size setting. Add a rem term.
  • MIN larger than MAX. The result is always MIN, which is rarely what was meant.
  • Limits in px for font sizes. They cap the text even for readers who need it larger. Use rem.

Frequently Asked Questions

What does clamp() do in CSS?

clamp(MIN, PREFERRED, MAX) uses the preferred value while it stays between the two limits, and the nearest limit otherwise. font-size: clamp(1rem, 4vw, 2rem) follows 4% of the viewport width but never goes below 1rem or above 2rem.

How do I make a responsive font size with clamp?

Put a viewport-based value in the middle and fixed limits on the sides, and mix rem into the middle so the text still follows the reader's font size setting: font-size: clamp(1.5rem, 1rem + 2vw, 3rem);.

What happens if the minimum is larger than the maximum in clamp()?

The minimum wins. clamp(3rem, 5vw, 2rem) always resolves to 3rem, because clamp() applies the minimum after the maximum.

What is the difference between min() and max() in CSS?

min() returns the smallest of its values, so it acts as an upper limit: width: min(100%, 600px) is never wider than 600px. max() returns the largest, so it acts as a lower limit: font-size: max(1rem, 2vw) is never smaller than 1rem.

Is clamp() supported in all browsers?

Yes, clamp(), min() and max() work in all current versions of Chrome, Edge, Firefox and Safari, and can be used in any property that takes a length, number, percentage or angle.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED