We are experiencing higher levels of website traffic, we are trying to expand. Thank you for your understanding.
CSS

Fluid Typography with CSS clamp(): Stop Writing Media Queries for Font Sizes

How CSS clamp() replaces font-size media queries with one line of fluid math. Includes the linear interpolation formula, accessibility rules, and examples.

Start reading Use tools
Fluid Typography with CSS clamp(): Stop Writing Media Queries for Font Sizes cover art

Open a stylesheet from a few years ago and you will find this pattern: a base font size, then a media query at 768px bumping the headings, then another at 1024px, maybe one more at 1440px. Four declarations to express one idea, "this heading should be bigger on bigger screens," and the type still jumps awkwardly at every breakpoint instead of scaling smoothly between them. CSS clamp() replaces the whole stack with one line that scales continuously. Here is how it works, how to compute the values correctly, and where the sharp edges are.

What clamp() does

clamp(MIN, PREFERRED, MAX) resolves to the preferred value, bounded on both sides. The trick that makes it fluid: the preferred value mixes viewport units with fixed units, so it changes as the viewport changes, while the bounds keep it sane at the extremes.

h1 {
  font-size: clamp(2rem, 1.2rem + 3.5vw, 3.5rem);
}

Reading it: never smaller than 2rem (32px), never larger than 3.5rem (56px), and in between, scale as 1.2rem + 3.5vw. At a 375px viewport that middle expression is 19.2px + 13.1px, which is below the floor, so the floor wins. At 1440px it is 19.2px + 50.4px, above the ceiling, so the ceiling wins. Between roughly 460px and 1190px, the size glides smoothly through every value from 32px to 56px. No breakpoints, no jumps.

The formula: stop guessing the middle value

Most clamp() tutorials wave at the preferred value as "something with vw in it, tweak until it looks right." You can do better. What you actually want is: size A at viewport width X, size B at viewport width Y, linear in between. That is a line through two points, and the slope-intercept math gives exact coefficients.

Say you want 18px body text at a 360px viewport and 21px at 1280px:

slope = (21 - 18) / (1280 - 360) = 0.00326
vw coefficient = slope * 100 = 0.326vw
intercept = 18 - (0.00326 * 360) = 16.83px = 1.052rem
body {
  font-size: clamp(1.125rem, 1.052rem + 0.326vw, 1.3125rem);
}

That single declaration hits exactly 18px at 360px wide and exactly 21px at 1280px wide, with perfect linear interpolation between. The arithmetic is mechanical, which is why we built a CSS Clamp Calculator that takes your two sizes and two viewport widths and emits the finished declaration. Compute once, paste, done.

The accessibility rule you cannot skip

Here is the sharp edge that disqualifies half the clamp() examples on the internet: a preferred value built only from vw units does not respond to browser zoom or the user's font-size setting. font-size: 4vw is 4 percent of the viewport no matter how far the user zooms text, which fails WCAG 1.4.4 (text must be resizable to 200 percent).

The fix is exactly the formula above: always include a rem term in the preferred expression. 1.052rem + 0.326vw scales with user preferences through the rem component while staying fluid through the vw component. If you remember one thing from this article: never ship a clamp() whose middle value has no rem in it. Then verify by zooming to 200 percent and confirming the text actually grows.

Building a fluid type scale

One fluid size is nice; a system is better. Define your scale as custom properties and the whole site moves together:

:root {
  --text-sm:   clamp(0.875rem, 0.84rem + 0.15vw, 0.96rem);
  --text-base: clamp(1.125rem, 1.05rem + 0.33vw, 1.31rem);
  --text-lg:   clamp(1.35rem,  1.22rem + 0.57vw, 1.67rem);
  --text-xl:   clamp(1.62rem,  1.41rem + 0.93vw, 2.14rem);
  --text-2xl:  clamp(1.94rem,  1.61rem + 1.47vw, 2.77rem);
  --text-3xl:  clamp(2.33rem,  1.81rem + 2.3vw,  3.55rem);
}

h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-2xl); }

Notice the ratios widen as sizes grow: small text barely changes across viewports (a 14px caption does not need to become 22px on desktop), while display headings swing dramatically. A common approach uses a 1.2 ratio between steps on mobile and 1.28 on desktop, which falls naturally out of computing each step's min from the mobile scale and max from the desktop scale.

Beyond font-size: fluid spacing

The same math applies anywhere a length lives. Section padding that breathes with the viewport:

.section {
  padding-block: clamp(3rem, 2rem + 4.5vw, 7rem);
}

.container {
  padding-inline: clamp(1rem, 0.5rem + 2.5vw, 3rem);
}

Fluid spacing is arguably a bigger win than fluid type: spacing media queries outnumber font-size media queries in most real stylesheets, and they all collapse the same way. Gap, margin, border-radius on large cards, even icon sizes all take clamp() happily.

Edge cases and gotchas

  • Container queries change the unit. If a component should size against its container rather than the viewport, use cqi units inside a container query context instead of vw. Same formula, swap the unit and measure container widths instead of viewports.
  • vw includes the scrollbar on Windows. 100vw is the viewport including the scrollbar gutter in classic scrollbar configurations, so computed sizes can run a few pixels larger than your math at exact breakpoints. The error is under one percent for typography; do not chase it.
  • Extreme aspect ratios. A 280px smartwatch-class viewport or a 3440px ultrawide will sit pinned at your min and max. That is the design working, not failing; choose bounds you would be happy to see frozen.
  • Line height should not be clamped independently. Use a unitless line-height: 1.5 and let it scale with the fluid font size, or you will create combinations that never had a designer's eye on them.
  • Negative slopes work too. Nothing requires the value to grow with the viewport. A letter-spacing that tightens as headings get larger, or a horizontal padding that shrinks on wide screens to favor a centered column, is just a formula with size A larger than size B. The same two-point math produces a negative vw coefficient and clamp() handles it fine, though you swap the min and max bounds.
  • Test the inheritance chain. A clamp() on html changes what rem means everywhere, including inside other clamp() expressions. Either clamp the root or the components, not both, unless you have done the compounding math deliberately.

Browser support and fallbacks

Support is no longer a concern in 2026: clamp() has shipped in every evergreen browser since 2020, and the last holdouts (pre-Chromium Edge, old Samsung Internet builds) are statistical noise for most audiences. If your analytics say otherwise, the fallback pattern is the usual two-declaration cascade:

h1 {
  font-size: 2.5rem;                              /* fallback */
  font-size: clamp(2rem, 1.2rem + 3.5vw, 3.5rem); /* modern */
}

Browsers that do not understand clamp() ignore the second line and keep the fixed size; everyone else gets fluid type. There is no need for @supports here because the override is harmless. The related functions min() and max() shipped on the same timeline and are worth knowing: width: min(100%, 65ch) is a one-line readable-measure container that replaces the classic max-width-plus-width pair.

When media queries are still right

clamp() interpolates a value; it does not change structure. Layout shifts, a sidebar collapsing, a nav becoming a hamburger, grid columns reflowing, still belong in media or container queries. The clean division: continuous properties get clamp(), discrete state changes get queries. Stylesheets organized this way end up with a handful of structural breakpoints and zero font-size breakpoints, which is the right shape.

Do the math once, with a tool

The linear interpolation formula is simple but tedious, and hand-tweaked vw coefficients are how accessibility bugs sneak in. Our free CSS Clamp Calculator takes your minimum size, maximum size, and the two viewport widths they should map to, and produces the exact rem-plus-vw declaration, accessible by construction because the rem term is part of the formula. Pair it with the Aspect Ratio Calculator for fluid media sizing, and if you are building out the rest of your visual system, the Gradient Generator and Box Shadow Generator cover the other fiddly-math corners of CSS.

Keep reading

More practical notes from the same toolbox.

View all articles
Meta Tags That Actually Matter in 2026 (SEO and Social) cover art
HTML

Meta Tags That Actually Matter in 2026 (SEO and Social)

Which meta tags affect rankings, click-through, and social sharing in 2026, which are dead weight, and co…

6 min read Jun 6
JSON Formatting and Validation: A Practical Guide cover art
JSON

JSON Formatting and Validation: A Practical Guide

A practical guide to JSON syntax rules, the errors that actually break parsers, validation strategies, an…

7 min read May 29
HTML Email Coding: Why Your Beautiful CSS Breaks in Outlook cover art
HTML

HTML Email Coding: Why Your Beautiful CSS Breaks in Outlook

Why modern CSS fails in email clients, what Outlook actually renders with, and the table-based, inline-st…

6 min read May 26

Put this into practice

Try the free HTML, CSS, JSON, and accessibility tools. No sign-up, no uploads, everything runs in your browser.

Open the toolbox