nuzairb@gmail.com— press E to copy
DESIGN ENGINEERING

Fluid Type Is Not Just clamp()

PUBLISHED ON:May 4, 2026

You copy a clamp() value from a tutorial. Paste it on the heading. Resize the browser — looks great. You move on.

Then you add a subheading. Give it its own clamp(). Add a caption below that. Resize the browser again. The heading gets enormous. The subheading stays medium. The caption barely moves.

The hierarchy collapses. At a wide viewport, everything feels like it's at a different zoom level. At a narrow one, the heading and body are nearly the same size.

The problem isn't clamp(). The problem is applying it per element, without a system. Three independent clamp values do not make a type scale. They make three independently fluid sizes that happen to coexist on the same page.

What a type scale actually is

A type scale is a ratio — not a list of sizes.

The Perfect Fourth is a common one: 1.333. Each level is 1.333× the one below it. If body text is 16px, H3 is ~21px, H2 is ~28px, H1 is ~37px, Display is ~49px. Every size in the system derives from one base.

The fluid part: the base responds to viewport width. And because every other size derives from that base, the whole scale shifts together. Pull one string — the ratio does the rest.

This is what separates a system from a collection of clamp() calls. In a system, the relationships between sizes are preserved at every viewport width. A display heading that is 3× body text at 320px is still 3× body text at 1440px. The hierarchy is invariant.

When you write independent clamp() values, you are implicitly defining different relationships at different widths. You probably didn't mean to. The type scale system makes the relationship explicit — and keeps it.

Interactive demo

320px

DISPLAY

Interfaces

H1

That feel inevitable

H2

Speed, precision, craft

H3

Every pixel is a decision

BODY

The difference between a design that works and one that resonates is rarely a single choice.

CAPTION

TYPOGRAPHY · DESIGN SYSTEMS

Mobile · 320Tablet · 768Desktop · 1440

What you just saw

Display went from 48px at 320 to 96px at 1440 — exactly 2×. Body barely moved: 14px to 16px.

That differential is intentional. Display type earns its drama at large sizes because it sits far from the base in the scale — several ratio steps up. It has more distance to travel. Body text is the base. It earns legibility at small sizes precisely because it moves least.

A few other things worth noting. Letter-spacing on the display heading tightened as viewport width increased. This is deliberate: tight tracking keeps large display type from feeling sparse and loosely assembled. It's a property of size, not role.

Line-height on body did not move. That's also deliberate. Line-height is a property of how that text is read — it belongs to the role, not the size. A paragraph stays readable for the same reason at 14px and 16px.

clamp() handles the size. The system handles everything else that changes with size.

The principle

clamp() is the output of a system, not the system itself.

Once you have a base size and a ratio, the clamp values follow automatically. You're not guessing. You're computing.

/* Base: 16px → 18px across 320px → 1440px */
--text-base:    clamp(1rem, 0.9643rem + 0.1786vw, 1.125rem);

/* × 1.333 (Perfect Fourth) */
--text-h3:      clamp(1.333rem, 1.2854rem + 0.2380vw, 1.5rem);    /* base × 1.333 */
--text-h2:      clamp(1.777rem, 1.7142rem + 0.3170vw, 2rem);      /* base × 1.333² */
--text-h1:      clamp(2.369rem, 2.2861rem + 0.4234vw, 2.667rem);  /* base × 1.333³ */
--text-display: clamp(3.157rem, 3.0451rem + 0.5639vw, 3.553rem);  /* base × 1.333⁴ */

Every value is derived. Change the base, every other size updates proportionally. Change the ratio, the whole scale rebalances.

Most people work backwards — pick a clamp() that looks right, wonder why the scale feels off at certain widths. The values are not the problem. The missing system is.

Define the system first. Let the values follow from it.

Articles in the Same Series