How to fluid typography in the wild: patterns and ratios
- Step 1Pick the pattern you are recreating — Decide whether you are building a hero (wide range, big impact), a section heading (mid range), or body copy (narrow range). The pattern dictates how far apart your Min px and Max px should be.
- Step 2Choose the viewport range to interpolate over — Most production sites interpolate from a small-phone width (320) to a desktop width (1280 or 1440). Set **Min vw** and **Max vw** to those. The size hits Min px at Min vw and Max px at Max vw, and pins outside the range.
- Step 3Set the size bounds for that pattern — Hero: roughly 40→96px. Heading: 24→40px. Body: 16→18px. Enter them as **Min px** and **Max px** (Min allows 8–40, Max allows 12–120, so the whole hero range fits).
- Step 4Generate and read the slope — Click **Generate**. The vw term in the output is the slope — a hero might be 5.000vw (fast growth) while body is ~0.18vw (barely perceptible). Larger slope = more dramatic scaling, which is exactly the hero/body distinction.
- Step 5Apply to the selector — Paste the `font-size:` line onto your `h1`, `h2` or `p`. The output also gives you `--font-size-fluid` if you prefer a variable. Below your Min vw the text stays at the floor; above your Max vw it stays at the ceiling.
- Step 6Sanity-check at in-between widths — Because fluid interpolates, check 480 and 1024 in addition to the breakpoints. A hero that looks great at 320 and 1440 can feel oversized at 700px if the slope is steep — tweak Min/Max or the viewport range and regenerate.
Common production patterns and their exact clamp()
The min/max ranges that recur on modern marketing sites, with the literal expression this generator returns (root 16, 3 decimals).
| Pattern | Min/Max px | Viewport range | Generated clamp() |
|---|---|---|---|
| Hero headline | 40 → 96 | 320 → 1440 | clamp(2.500rem, 1.500rem + 5.000vw, 6.000rem) |
| Bold hero (steeper) | 32 → 80 | 320 → 1280 | clamp(2.000rem, 1.000rem + 5.000vw, 5.000rem) |
| Section heading | 24 → 40 | 320 → 1440 | clamp(1.500rem, 1.214rem + 1.429vw, 2.500rem) |
| Subheading | 20 → 28 | 320 → 1280 | clamp(1.250rem, 1.083rem + 0.833vw, 1.750rem) |
| Body copy (subtle) | 16 → 18 | 320 → 1440 | clamp(1.000rem, 0.964rem + 0.179vw, 1.125rem) |
Reading the slope: how aggressive each pattern grows
The vw term in each expression is the growth rate. This is what visually separates a hero from body copy.
| Pattern | vw slope | Feel |
|---|---|---|
| Hero 40→96 / 320→1440 | 5.000vw | Dramatic — text grows fast with width |
| Heading 24→40 / 320→1440 | 1.429vw | Clearly visible, not theatrical |
| Subheading 20→28 / 320→1280 | 0.833vw | Gentle |
| Body 16→18 / 320→1440 | 0.179vw | Almost imperceptible — readability first |
Inputs the tool accepts for these patterns
All real-world patterns above fit within the schema's ranges — useful to know before you start.
| Field | Schema range | Covers |
|---|---|---|
| Min px | 8 – 40 | Body floor (16) up to a large hero floor (40) |
| Max px | 12 – 120 | Body ceiling (18) up to oversized hero (96+) |
| Min vw | 200 – 1000 | Tiny phones (320) and below |
| Max vw | 800 – 2400 | Standard desktop (1280/1440) up to ultrawide |
Cookbook
Each recipe is a recognisable production pattern reduced to the four inputs you type here, with the exact clamp() the tool returns. Brand names are illustrative of the style, not literal copies of any site's CSS.
Big hero headline, phone to ultrawide
ExampleThe flagship use of fluid type: a headline that owns the viewport at every size. 40px on a phone, 96px on a wide desktop, capped so it never explodes past 1440px.
Inputs: Min 40px · Max 96px · Min vw 320 · Max vw 1440
Output:
h1 { font-size: clamp(2.500rem, 1.500rem + 5.000vw, 6.000rem); }
Slope 5.000vw → fast growth. Pinned at 6rem above 1440px.Subtle body copy (the readability pattern)
ExampleSites that care about reading comfort keep body type in a tight range so paragraphs stay the right size everywhere. The 0.179vw slope is intentional restraint.
Inputs: Min 16px · Max 18px · Min vw 320 · Max vw 1440
Output:
p { font-size: clamp(1.000rem, 0.964rem + 0.179vw, 1.125rem); }
Readers never notice the change — which is the point.Mid-range section heading
ExampleSection titles want visible scaling without competing with the hero. A 24→40px range over the default viewports gives a 1.429vw slope.
Inputs: Min 24px · Max 40px · Min vw 320 · Max vw 1440
Output:
h2 { font-size: clamp(1.500rem, 1.214rem + 1.429vw, 2.500rem); }Cap growth at 1280 for app-style layouts
ExampleProduct/app pages often max out usefully at 1280, not 1440. Setting Max vw to 1280 makes the hero reach full size sooner and stop there.
Inputs: Min 32px · Max 80px · Min vw 320 · Max vw 1280
Output:
h1 { font-size: clamp(2.000rem, 1.000rem + 5.000vw, 5.000rem); }
Reaches 80px at 1280px and stays there on wider screens.A full headline block with family and fluid size
ExamplePair the generated size with a system fallback stack and font-display so the headline behaves on slow networks. Generate the family stack with the system-font-stack-generator.
h1 {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-size: clamp(2.500rem, 1.500rem + 5.000vw, 6.000rem);
line-height: 1.05;
}
/* @font-face elsewhere should use font-display: swap
so the fallback shows immediately on slow loads. */Edge cases and what actually happens
Every row below was probed against the live API. Some documented requirements (alphabetical axis order, numerical tuple order) are not actually enforced in practice — useful to know if you've been blaming the wrong thing for a 400.
Hero text too big at mid widths
Tune the slopeA wide range over a wide viewport span can look fine at 320 and 1440 but oversized around 700–900px because the slope is steep. Either narrow the size range, raise Min vw, or lower Max vw and regenerate. The generator makes this a one-click re-run, so iterate against real in-between widths.
Body type creeps too large on desktop
Avoidable — keep the range tightProduction body copy almost always uses a narrow range (16→18, occasionally 16→20). Going to 16→24 makes desktop paragraphs noticeably bigger and hurts line length. The tool allows the wide range, but the well-read pattern is restraint — keep Max px close to Min px for body.
Ultrawide monitor with no ceiling in mind
Solved by Max vwNaive vw sizing explodes on a 2560px screen. clamp()'s ceiling fixes this, and the generator always emits it. Set Max vw to where you want growth to stop (up to 2400 in the schema) — past that width the size is pinned at the Max rem value, exactly as production heroes behave.
Very small phones below your Min vw
Expected — pinned at floorIf your Min vw is 320 but a user is on a 280px-wide device, the size stays at the Min rem floor rather than shrinking further. That is usually what you want — text does not get tinier on the smallest screens. If you need it to scale below 320, lower Min vw (the field allows down to 200).
Hero needs 100px+ — Max px tops out at 120
Supported within rangeThe Max px field allows up to 120, so most heroes fit. If you want a display size above 120px, the tool cannot produce it — write that one clamp() by hand using the tool's formula (Max rem = px ÷ 16) as a template, or scale your design down to fit.
Copying a site's slope but it looks different
Check the root sizeIf you matched another site's clamp() numbers but the rendered size differs, the likely cause is a different html root size. This generator assumes 16. A site running an 18px or 20px root will render the same rem values larger. Normalise your root to 16 or recompute with your actual root.
Negative slope from a typo'd hero
By design — verify before shippingSwapping Min and Max px (entering the big number as Min) produces a valid clamp() that shrinks as the screen grows — the opposite of a hero. The tool does not reject inverted bounds, so double-check Max px is the larger number for every pattern.
Max vw set at or below Min vw
Error — rejectedIf you fat-finger Max vw to a value ≤ Min vw, the tool throws Max viewport must be greater than min viewport. and emits nothing. Fix the viewport pair and regenerate.
It does not preview against your actual font
By design — generative toolThe generator is font-agnostic: it cannot show how the clamp() looks in your specific typeface because it never reads a font file. Paste the output into your page to see the real rendering, or analyse the font's metrics with the font-metrics-analyzer if you want sizes tuned to its x-height.
Frequently asked questions
What min/max ranges do real sites use for heroes?
Roughly 40→96px for a big-impact hero, or 32→80px for a slightly more restrained one, interpolated from ~320 to 1280/1440. The generator turns those into expressions like clamp(2.500rem, 1.500rem + 5.000vw, 6.000rem) directly.
And for body copy?
A tight 16→18px (occasionally 16→20px) over the default viewports. The slope ends up around 0.18vw — almost imperceptible, which is exactly what production sites want so paragraphs stay readable at every width.
How do I read how aggressive a pattern is?
Look at the vw term in the output. A hero at 5.000vw grows fast; body at 0.179vw barely changes. The vw slope is the single number that distinguishes dramatic display scaling from subtle body scaling.
Why does my recreated pattern look bigger than the original?
Almost always a root-size mismatch. This generator assumes a 16px root for the rem conversion. If the site you copied runs an 18px or 20px html root, the same rem values render larger. Set your root to 16 or recompute with your real root.
How do I stop the hero exploding on a 4K screen?
Set Max vw to where you want growth to stop (up to 2400). clamp()'s ceiling pins the size past that width — the generator always includes it, which is the same mechanism production heroes use to stay sane on ultrawide displays.
Can I make a hero larger than 120px?
Not through the tool — Max px tops out at 120. For an oversized display size, hand-write that single clamp() using the tool's formula (Max rem = px ÷ 16, slope = (max−min)/(maxVw−minVw)) as the template, or rein the design in to fit.
Should body text scale at all, or stay fixed?
A small fluid range (16→18) is common and feels polished, but a fixed 16px or 1rem body is perfectly fine and even simpler. If you keep it fixed, set Min px = Max px and the tool returns a zero-slope clamp() — or just write font-size: 1rem.
Which extra widths should I test?
Add 480 and 1024 to your usual 320/768/1280. Fluid interpolation means the in-between widths are where a too-steep slope shows up — a hero can look perfect at the endpoints and oversized at 700px.
Does the tool show me the font rendered at each size?
No — it is font-agnostic and never loads a font file, so there is no live preview. Paste the clamp() into your page to see the real rendering. Use the font-metrics-analyzer if you want sizes tuned to a specific font's metrics first.
What pairs well with the generated size for a headline?
A family stack from the system-font-stack-generator so there is always a sensible fallback, and a loading strategy from the font-display-strategy tool so the headline appears fast on slow networks. The clamp() handles size; those handle family and loading.
Can I get a whole scale of these patterns at once?
Use the typography-scale-builder. Give it a base size and a ratio and it emits a fluid clamp() per step (xs → 4xl) in one run, which covers hero, headings and body together. This clamp tool is one pattern at a time.
Is any data uploaded to recreate these patterns?
No. The generator runs entirely in your browser with no file input — it just computes the clamp() arithmetic. Nothing leaves your machine.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.