When you build responsive designs, the statement "elements should grow as the screen grows" is true. But "they should grow and shrink without limit" is not. That gap is exactly where the fundamental difference between vw and clamp() lives.
1. vw: Directly Proportional to the Screen
The vw unit is directly proportional to the viewport width (1vw = 1% of it). Set font-size: 5vw and your text renders at 100px on a 2000px screen — and at 18px on a 360px phone.
2. clamp(): Freedom, With Boundaries
The clamp() function takes three arguments: a minimum, a preferred value, and a maximum. The browser computes the preferred value, then uses the minimum if it falls below it, or the maximum if it goes above it.
/* Syntax: clamp(MIN, PREFERRED, MAX) */
h1 { font-size: clamp(18px, 5vw, 32px); }
The code above behaves like this:
- No matter how narrow the screen gets, the font never drops below 18px.
- No matter how wide the screen gets, the font never grows beyond 32px.
- In between (360–640px), it scales fluidly at 5% of the screen width.
It's a good example for learning the syntax, but it only actually scales between 360px and 640px, so it's already stuck at the maximum from tablets up. It also uses only px and vw, so it ignores the user's font-size setting. In production, you calculate the preferred value for the screen range you want and mix in rem.
3. Calculating the Preferred Value
To get size a at screen width A and size b at screen width B, build the preferred value as "intercept (rem) + slope (vw)":
slope = (b - a) / (B - A)
intercept = a - slope * A
preferred = intercept (px / 16 = rem) + slope * 100 (vw)
/* Example: 18px at 360px → 32px at 1280px */
slope = (32 - 18) / (1280 - 360) = 0.015217 → 1.5217vw
intercept = 18 - 0.015217 * 360 = 12.52px → 0.7826rem
h1 { font-size: clamp(1.125rem, 0.7826rem + 1.5217vw, 2rem); }
This gives 18px at 360px, about 24.2px at 768px, and 32px from 1280px up. You don't have to do the math by hand: enter the min/max viewport and sizes in our Clamp Generator to get a clamp() value in rem or px (rem recommended), and drag the slider to preview the real size at each screen width. It can also build a whole type scale for headings and body text at once.
4. Why You Should Mix in rem
Using clamp() doesn't make text accessible by itself. Here's how three approaches compare in a 500px-wide browser window (size as shown on screen):
| Declaration | Default | 200% zoom | Font setting 32px |
|---|---|---|---|
5vw |
25px | 25px (1×) | 25px (1×) |
clamp(18px, 5vw, 32px) |
25px | 36px (1.44×) | 25px (1×) |
clamp(1.125rem, 0.7826rem + 1.5217vw, 2rem) |
~20.1px | 36px (~1.79×) | 36px (~1.79×) |
Zooming the browser to 200% halves the window's CSS width (to 250px), which halves every vw value. So vw-only text doesn't grow at all when zoomed, and a px-based clamp responds partly to zoom but ignores the font-size setting. With rem for the min and max and rem mixed into the preferred value, text grows in both cases — which is what WCAG 1.4.4 (Resize Text, 200%) is about.
5. Key Differences at a Glance
| Aspect | vw unit | clamp() function |
|---|---|---|
| Range limits | None (scales without bounds) | Yes (min/max built in) |
| Media query dependence | High (needs per-breakpoint fixes) | Low (one function handles it) |
| Code complexity | Simple | Slightly more complex, but explicit |
| Text legibility / accessibility | Fragile (ignores zoom and font-size settings) | Strong when min/max use rem and the preferred value mixes rem + vw |
| Browser support | All browsers | All major browsers since 2020 |
6. min(), max(), and cqi Units
If you only need an upper or a lower bound, min() or max() is enough. For example, width: min(90vw, 1200px) means "90% of the screen, but no more than 1200px."
To size things relative to a parent element instead of the screen, use the container query unit cqi (1cqi = 1% of the container's width). It has been supported in all major browsers since 2023 and is handy for components like cards whose width depends on where they're placed.
/* 16px at a 200px-wide card → 24px at 600px and up */
.card { container-type: inline-size; }
.card h3 { font-size: clamp(1rem, 0.75rem + 2cqi, 1.5rem); }
7. What Do Developers Use in Production?
In real-world projects today, clamp() is the most common way to implement fluid typography — text that scales smoothly with the screen width. The usual approach is to pick a screen range, calculate rem-based preferred values, and manage heading and body sizes as CSS variables.
Conclusion
Think of vw as the engine and clamp() as the limiter that keeps that engine's speed in check. Calculate the preferred value for the screen range you want and mix in rem, and you get font sizes that respond to both screen size and user settings. To convert design px values, use the PX to VW converter or the PX to REM converter.