Fluid Font Sizing with clamp()
The Problem
Responsive typography traditionally requires multiple media queries to adjust font sizes at different breakpoints. This creates abrupt jumps between sizes and produces verbose, hard-to-maintain CSS. AI agents frequently generate fixed px or rem values at arbitrary breakpoints instead of using fluid scaling, resulting in text that is either too small on mobile or too large on desktop, with jarring transitions between breakpoints.
The Solution
The CSS clamp() function enables fluid typography in a single line, smoothly scaling font sizes between a minimum and maximum based on viewport width. The syntax is clamp(min, preferred, max), where the preferred value typically combines a rem base with a vw component for viewport-relative scaling.
The Formula
The preferred (middle) value in clamp() should be calculated as a linear function of viewport width. The general formula is:
preferred = base-rem + (slope × 1vw)
Where the slope is derived from the desired font-size range and viewport range:
slope = (max-size - min-size) / (max-viewport - min-viewport)
Code Examples
Basic Fluid Typography
/* Body text: scales from 16px to 20px between 320px and 1200px viewports */
body {
font-size: clamp(1rem, 0.909rem + 0.45vw, 1.25rem);
}
/* h1: scales from 28px to 48px */
h1 {
font-size: clamp(1.75rem, 1.295rem + 2.27vw, 3rem);
}
/* h2: scales from 24px to 36px */
h2 {
font-size: clamp(1.5rem, 1.227rem + 1.36vw, 2.25rem);
}
/* h3: scales from 20px to 28px */
h3 {
font-size: clamp(1.25rem, 1.068rem + 0.91vw, 1.75rem);
}
Fluid Type Scale System
:root {
/* Viewport range: 320px to 1200px */
--step--1: clamp(0.833rem, 0.787rem + 0.23vw, 1rem);
--step-0: clamp(1rem, 0.909rem + 0.45vw, 1.25rem);
--step-1: clamp(1.2rem, 1.042rem + 0.79vw, 1.563rem);
--step-2: clamp(1.44rem, 1.186rem + 1.27vw, 1.953rem);
--step-3: clamp(1.728rem, 1.339rem + 1.95vw, 2.441rem);
--step-4: clamp(2.074rem, 1.494rem + 2.9vw, 3.052rem);
}
body {
font-size: var(--step-0);
}
h1 {
font-size: var(--step-4);
}
h2 {
font-size: var(--step-3);
}
h3 {
font-size: var(--step-2);
}
small {
font-size: var(--step--1);
}
With Container Queries
/* Fluid sizing relative to container width instead of viewport */
.card-title {
font-size: clamp(1rem, 0.5rem + 3cqi, 1.5rem);
}
Common AI Mistakes
- Using fixed
pxorremvalues with media query breakpoints instead ofclamp(), creating abrupt size jumps - Omitting the
remcomponent in the preferred value (using onlyvw), which breaks zooming and accessibility - Setting minimum values too small (below
1rem/ 16px for body text), making text unreadable on mobile - Not testing the formula at extreme viewport widths, leading to absurdly large text on ultrawide monitors
- Using
calc()withvwalone (e.g.,calc(1rem + 1vw)) without upper or lower bounds, whichclamp()naturally provides - Applying fluid sizing to every text element when only headings and display text benefit from it — body text often works fine at a fixed
1rem
When to Use
- Headings and display text that need to scale between mobile and desktop
- Type scale systems where every step should fluidly adjust
- Hero sections with large text that needs to shrink on small screens
- Any scenario where breakpoint-based font-size changes cause visible jumps
Avoid using clamp() for:
- Body text where
1remis perfectly adequate at all sizes - Text inside components with fixed dimensions
- Situations where precise control at specific breakpoints is required