w3tweaks.com · CSS Tutorial

CSS clamp()

Fluid typography · Responsive spacing · Zero media queries

Tab 1

Live clamp() Explorer

Drag the sliders to set min, preferred, and max. See the zone graph update — blue is where min applies, green is where the fluid preferred value is active, red is where max takes over.

14px
4vw
36px
800px
Active zone Fluid range
320px 800px 1400px
Current: font-size: 32px (at 800px viewport)
Preview text
font-size: clamp(14px, 4vw, 36px);
The CSS Math Function Family
min(a, b)
↘ smallest
width: min(50%, 400px);
/* 50% but never over 400px */

The browser uses whichever value is smaller. Equivalent to clamp(none, a, b).

max(a, b)
↗ largest
width: max(200px, 30%);
/* 30% but never under 200px */

The browser uses whichever value is larger. Equivalent to clamp(a, b, none).

clamp(min, val, max)
↕ both
font-size: clamp(1rem, 4vw, 2rem);
/* bounded on both sides */

Equivalent to max(MIN, min(VAL, MAX)). Combines both min and max in one declaration.

Why the preferred value is often vw + rem: Using bare vw (like 4vw) creates sizes that can be extreme at edge viewports. Adding a rem offset like 0.5rem + 2vw controls the slope better: the rem sets the base, the vw controls how fast it scales. See the Typography Calculator tab for the exact formula.
Tab 2

Fluid Typography Calculator

Enter your desired font size at two viewport widths. The calculator derives the exact clamp() formula that interpolates perfectly between them — no guessing the vw value.

Font size targets
Min size px
Max size px
Viewport breakpoints
Min viewport px
Max viewport px
Root font size
Base px
Generated clamp() formula
font-size: clamp(
  1rem,
  0.5rem + 2.5vw,
  2rem
);
Grows from 16px at 320px viewport to 32px at 1280px viewport. The 2.5vw term controls the scaling rate.

Fluid heading text

Body text stays at a comfortable reading size. Resize the browser to see the heading scale smoothly.

Common Fluid Typography Scale (320px→1280px, base 16px)
xs text: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem)
body: clamp(1rem, 0.95rem + 0.25vw, 1.125rem)
h4: clamp(1.125rem, 1rem + 0.625vw, 1.5rem)
h3: clamp(1.25rem, 1rem + 1.25vw, 2rem)
h2: clamp(1.5rem, 1rem + 2.5vw, 3rem)
h1: clamp(2rem, 1rem + 5vw, 5rem)
WCAG accessibility requirement for clamped font sizes: When using clamp() for font-size, the maximum value must be at least 2× the minimum value (e.g. clamp(1rem, ..., 2rem)). This ensures the text can still grow 200% when the user activates browser zoom (WCAG 1.4.4 Resize Text — Level AA). If max is only 1.2× min, zooming to 200% may be prevented.
Tab 3

6 Real Patterns

Resize your browser window to see all of these adapting continuously — no breakpoints, no JavaScript.

🔤 Fluid Type Scale
Heading 1
Heading 2
Heading 3
Body paragraph — reads comfortably on any screen size because the font scale adapts with the viewport.
h1 { font-size: clamp(1.6rem, 4vw + .5rem, 3rem); }
h2 { font-size: clamp(1.2rem, 2.5vw + .5rem, 2rem); }
p { font-size: clamp(.875rem, 1vw + .3rem, 1rem); }

All headings scale proportionally without a single media query. The rem + vw pattern gives a gentler slope than bare vw.

📏 Optimal Line Length with ch
❌ No limit — too wide
This line has no maximum width limit. On a wide screen it stretches the full container, making it very hard to read because your eyes have to travel too far across the page.
✓ Clamped with ch — optimal
This line is constrained to between 45ch and 75ch — the typographic sweet spot for readability. It's never too narrow on mobile, never too wide on desktop.
.content {
  width: clamp(45ch, 70%, 75ch);
  /* 45–75ch: the readability sweet spot */
  margin-inline: auto;
}

ch is the width of the "0" character. 45–75 characters per line is the optimal readability range from typography research.

🃏 Fully Fluid Card Component

Zero media queries

Every property — padding, font size, border radius, button size — uses clamp(). Resize the browser and watch the whole card scale proportionally.

.card {
  padding: clamp(12px, 3vw, 28px);
  border-radius: clamp(6px, 1vw, 16px);
  font-size: clamp(.85rem, 1.2vw + .3rem, 1rem);
}

Apply clamp() to every spatial property for a fully fluid component — no breakpoints anywhere.

📦 Responsive Container
width: clamp(200px, 90%, 860px)
.container {
  width: clamp(200px, 90%, 860px);
  margin-inline: auto;
}

/* or with padding instead */
.container {
  max-width: 860px;
  padding-inline: clamp(16px, 5vw, 80px);
}

Never exceeds 860px on wide screens. Never drops below 200px on narrow ones. The gutters (5vw) grow with the viewport without ever being too tight or too wide.

✨ Fluid Border Radius & Shadow
Hover
Cards
.card {
  border-radius: clamp(4px, 1.5vw, 20px);
  box-shadow:
    0 clamp(2px, .5vw, 8px)
    clamp(8px, 2vw, 32px)
    rgba(163, 230, 53, .2);
}

Border radius and shadow depth scale with viewport — cards feel proportional on any screen size. Tiny radii on mobile; generous, app-like radii on desktop.

📐 Fluid Spacing Token System
:root {
  --space-xs: clamp(4px, 1vw, 8px);
  --space-sm: clamp(8px, 2vw, 16px);
  --space-md: clamp(16px, 4vw, 32px);
  --space-lg: clamp(24px, 6vw, 48px);
  --space-xl: clamp(40px, 8vw, 80px);
}

/* Components just use the tokens */
.section { padding: var(--space-xl) var(--space-md); }
.card { gap: var(--space-sm); }

Combine with CSS custom properties for a design token system where all spacing automatically scales with the viewport — one definition, universal fluidity.

Gotcha: min > max — browser silently uses min
If the minimum value is larger than the maximum, the browser uses the minimum value and ignores the maximum. No error, no warning. Example: clamp(400px, 50%, 200px) — the 200px max is ignored because min (400px) > max (200px). Always ensure min < max.
Read the tutorial