Tags: web-dev concept

Fluid Type and Space

Date: 2026-09-27


clamp(min, preferred, max), with a preferred value of rem + vw, scales a size continuously between two viewport widths instead of jumping at breakpoints. Each size is a straight line through two points. Keep a rem part in it, or text stops growing when the user zooms.


Fluid type and space means font sizes and spacing that interpolate linearly between a minimum at a small viewport and a maximum at a large one, using clamp(). When and where to use it — the top few steps of a scale, never body text — is covered in Type Scale. This note is the arithmetic, and what it does to spacing and zoom.

It’s a straight line

size
40px ┤                              ●━━━━━━━━━  max (clamped)
     │                          ╱
     │                      ╱
     │                  ╱         preferred = intercept + slope × viewport
     │              ╱
24px ┤━━━━━━━━━━━●                             min (clamped)
     └──────────┬──────────────────┬─────────
              320px              1280px         viewport width

Working out the preferred value

Target: 24px at a 320px viewport, rising to 40px at 1280px.

slope      = (max size − min size) / (max vw − min vw)
           = (40 − 24) / (1280 − 320)
           = 16 / 960
           = 0.01667          → per 100px of viewport, +1.667px
                              → as a vw value: 0.01667 × 100 = 1.667vw

intercept  = min size − slope × min vw
           = 24 − 0.01667 × 320
           = 24 − 5.33
           = 18.67px          → ÷ 16 = 1.167rem

check at 1280:  18.67 + 0.01667 × 1280 = 18.67 + 21.33 = 40px ✓
:root {
  --step-3: clamp(1.5rem, 1.167rem + 1.667vw, 2.5rem);   /* 24px → 40px */
}
h2 { font-size: var(--step-3); }

Nobody does this by hand more than twice. Generators produce the whole scale — Utopia is the widely used one — but knowing it’s a line through two points is what lets you sanity-check the output and debug a size that looks wrong.

Fluid space

The same mechanism applied to spacing tokens: section padding and gaps that grow with the viewport, so a layout doesn’t need a breakpoint just to add breathing room.

:root {
  --space-s:  clamp(1rem,   0.917rem + 0.417vw, 1.25rem);   /* 16px → 20px */
  --space-xl: clamp(2rem,   1.33rem + 3.33vw, 4rem);    /* 32px → 64px */
}
.section { padding-block: var(--space-xl); }

Small spaces barely need it; large ones benefit most. A 4px gap scaling to 5px is noise. Section padding scaling from 32px to 64px is the difference between cramped mobile and airy desktop — Spacing Systems.

Pair the steps so they move together (a heading’s size and the space above it), or the proportions drift between the two ends of the range.

The zoom problem

Browser zoom enlarges rem and px, but vw stays tied to the viewport — and zooming in makes the viewport narrower in CSS pixels, so the vw part shrinks.

font-size: 5vw            zoom 100% → 200%: text barely changes
                          ← fails the need to resize text to 200%

font-size: clamp(1.5rem, 1.167rem + 1.667vw, 2.5rem)   on a 1280px screen

zoom 100%   viewport 1280 CSS px   18.67 + 0.01667 × 1280 = 40.0 CSS px → 40px on screen
zoom 200%   viewport  640 CSS px   18.67 + 0.01667 ×  640 = 29.3 CSS px → 59px on screen
                                   ← 1.47× larger, not 2×
  • Never use vw alone for type. Always add a rem term
  • The steeper the slope, the less zoom helps. A gentle ratio between min and max keeps 200% zoom reachable [CHECK: the commonly cited rule is to keep max ≤ ~2.5× min for WCAG (Web Content Accessibility Guidelines) 1.4.4 resize-text compliance; verify against a current source before relying on it] — WCAG
  • Test at 200% zoom at both ends of the range, not just at the default

Failure modes

  • Unbounded vw — no max, so headlines become absurd on a 2560px monitor
  • Fluid body text — a comfortable reading size doesn’t depend on screen width, and shrinking it on mobile is exactly wrong
  • Min and max viewports that don’t match the design range. The line keeps changing below and above them, clamped only by the size limits
  • Mixing fluid and stepped values for related things, so they move out of proportion in the middle of the range

Where it connects