Screen-Width Based Font Size Definition
The Problem
Basic clamp() typography scales font size linearly across the entire viewport range. This works for simple cases, but falls short when you need precise control over how text scales within specific breakpoint ranges. For example, a site logo might need to:
- Stay at 15–24px within the
lgbreakpoint range (1024–1280px) - Scale to 24–30px within the
xlrange (1280–1536px) - Reach 30–36px in the
2xlrange (1536–1920px)
A single clamp() cannot express this piecewise scaling. You would need media queries with fixed sizes, creating jarring jumps — or a single clamp that doesn't precisely hit the sizes you want at each breakpoint boundary.
The Solution
Combine breakpoint-specific media queries with per-range clamp() values. Each breakpoint gets its own clamp() that smoothly scales within that range, and the ranges are stitched together so the maximum of one range equals the minimum of the next.
This article builds on Fluid Font Sizing with clamp(). Make sure you understand basic clamp() usage before reading further.
The Formula
For a given breakpoint range from startVw to endVw, scaling font size from minSize to maxSize:
slope = (maxSize - minSize) / (endVw - startVw)
intercept = minSize - slope × startVw
This gives you:
font-size: clamp(minSize, calc(intercept + slope × 1vw), maxSize);
For example, scaling 15px → 24px across the 1024px → 1280px range:
slope = (24 - 15) / (1280 - 1024) = 9 / 256 ≈ 0.03516 (3.516vw)
intercept = 15 - 0.03516 × 1024 = 15 - 36 ≈ -21px
Result: clamp(15px, calc(-21px + 3.516vw), 24px)
Verification: At 1024px → calc(-21 + 0.03516 × 1024) = calc(-21 + 36) = 15px. At 1280px → calc(-21 + 0.03516 × 1280) = calc(-21 + 45) = 24px.
Code Examples
Basic Segmented Fluid Font Size
.site-title {
/* Base: fixed size for small screens */
font-size: 15px;
}
/* lg: 1024px – 1280px → scale 15px to 24px */
@media (min-width: 1024px) {
.site-title {
font-size: clamp(15px, calc(-21px + 3.516vw), 24px);
}
}
/* xl: 1280px – 1536px → scale 24px to 30px */
@media (min-width: 1280px) {
.site-title {
font-size: clamp(24px, calc(-6px + 2.344vw), 30px);
}
}
/* 2xl: 1536px – 1920px → scale 30px to 36px */
@media (min-width: 1536px) {
.site-title {
font-size: clamp(30px, calc(6px + 1.563vw), 36px);
}
}
Note: The demos below use scaled-down breakpoints (320px / 500px / 768px) so the fluid scaling is visible within the preview iframe. The code examples above show production-appropriate breakpoints.
Design Token System with Segmented Scaling
Define a reusable token system where each font size step has precise per-breakpoint scaling:
:root {
/* Small screens: fixed base sizes */
--font-size-display: 24px;
--font-size-title: 20px;
--font-size-heading: 18px;
--font-size-body: 16px;
}
/* lg: 1024px – 1280px */
@media (min-width: 1024px) {
:root {
--font-size-display: clamp(28px, calc(-4px + 3.125vw), 36px);
--font-size-title: clamp(22px, calc(-2px + 2.344vw), 28px);
--font-size-heading: clamp(18px, calc(2px + 1.563vw), 22px);
--font-size-body: clamp(16px, calc(8px + 0.781vw), 18px);
}
}
/* xl: 1280px – 1536px */
@media (min-width: 1280px) {
:root {
--font-size-display: clamp(36px, calc(-24px + 4.688vw), 48px);
--font-size-title: clamp(28px, calc(-12px + 3.125vw), 36px);
--font-size-heading: clamp(22px, calc(2px + 1.563vw), 26px);
--font-size-body: clamp(18px, calc(8px + 0.781vw), 20px);
}
}
Calculating clamp() Values for Any Range
Here is a step-by-step example for calculating the clamp() preferred value for any viewport range.
Goal: Scale font from 22px at 1024px viewport to 28px at 1280px viewport.
Step 1: Calculate the slope
slope = (28 - 22) / (1280 - 1024)
= 6 / 256
≈ 0.02344
Step 2: Calculate the intercept (base offset in px)
intercept = minSize - slope × startVw
= 22 - 0.02344 × 1024
≈ 22 - 24
= -2px
Step 3: Assemble the clamp()
font-size: clamp(22px, calc(-2px + 2.344vw), 28px);
Verification: At 1024px viewport → calc(-2 + 0.02344 × 1024) = calc(-2 + 24) = 22px. At 1280px → calc(-2 + 0.02344 × 1280) = calc(-2 + 30) = 28px.
Full Page Header Example
A real-world example showing a site header with logo text that scales smoothly across all breakpoints:
Common AI Mistakes
- Using a single
clamp()across the full viewport range when precise per-breakpoint control is needed — the scaling rate cannot be tuned for different ranges - Forgetting to align the
maxof one range with theminof the next, causing visible jumps at breakpoint boundaries (e.g., 24px max at lg but 26px min at xl creates a 2px jump) - Getting the formula wrong — the denominator is the viewport range
(endVw - startVw), not(endVw - minSize). Mixing viewport width with font size produces incorrect slopes - Using
vwalone withoutcalc()offset —font-size: 2vwgives 20px at 1000px viewport but you cannot control where it starts and stops - Applying segmented clamp to body text or small UI labels where a single
clamp()or fixed size is sufficient — this technique is best for display and title text - Not verifying the math — always check that
calc(intercept + slope × startVw)equals your intended minimum size
When to Use
- Site logos and brand text that must hit exact sizes at specific breakpoints
- Design token font-size definitions where each token step needs independent scaling behavior
- Display headings in hero sections that require different scaling rates at different viewport ranges
- Any element where a single
clamp()doesn't give enough control over the scaling curve
Prefer a single clamp() (covered in Fluid Font Sizing) when:
- The scaling range is simple (one min → one max across all viewports)
- Pixel-precise control at breakpoint boundaries is not required
- You want minimal CSS for straightforward responsive text