Skip to content

Clamp & Fluid Typography

The clamp() function enables fluid, responsive values that scale smoothly between a minimum and maximum, eliminating the need for multiple breakpoints.

/* Multiple breakpoints for responsive typography */
h1 {
font-size: 24px;
}
@media (min-width: 480px) {
h1 {
font-size: 28px;
}
}
@media (min-width: 768px) {
h1 {
font-size: 36px;
}
}
@media (min-width: 1024px) {
h1 {
font-size: 42px;
}
}
@media (min-width: 1280px) {
h1 {
font-size: 48px;
}
}
/* Spacing with breakpoints */
.section {
padding: 20px;
}
@media (min-width: 768px) {
.section {
padding: 40px;
}
}
@media (min-width: 1024px) {
.section {
padding: 60px;
}
}

Problems:

  • Many breakpoints to maintain
  • Jarring jumps between sizes
  • Repetitive code
  • Difficult to keep consistent
  • Doesn’t scale smoothly
/* Single line replaces all breakpoints */
h1 {
font-size: clamp(1.5rem, 4vw + 1rem, 3rem);
}
.section {
padding: clamp(1.25rem, 5vw, 3.75rem);
}

Benefits:

  • Single declaration, no breakpoints
  • Smooth scaling between sizes
  • Built-in min and max constraints
  • Less code to maintain
  • Consistent scaling system
/* clamp(minimum, preferred, maximum) */
font-size: clamp(16px, 4vw, 32px);
/*
- Never smaller than 16px
- Scales with 4vw (4% of viewport width)
- Never larger than 32px
*/
/* Preferred value formula: */
/* preferred = (vw-unit) + (base-adjustment) */
/* Example calculation for 320px to 1200px viewport: */
/* font-size: clamp(1rem, 0.5rem + 2vw, 2rem); */
/* At 320px: 0.5rem + (320 × 0.02) = 0.5rem + 6.4px ≈ 1rem (min applies) */
/* At 760px: 0.5rem + (760 × 0.02) = 0.5rem + 15.2px ≈ 1.5rem */
/* At 1200px: 0.5rem + (1200 × 0.02) = 0.5rem + 24px ≈ 2rem (max applies) */
/* Takes the smallest value */
.container {
width: min(100%, 1200px);
/* Same as: max-width: 1200px; width: 100%; */
}
.card {
width: min(400px, 100% - 2rem);
}
/* Takes the largest value */
.element {
width: max(300px, 50%);
/* At least 300px, or 50% if larger */
}
.sidebar {
width: max(250px, 20vw);
}
/* Nested functions */
.container {
padding: max(1rem, min(3vw, 2rem));
}
/* clamp() is shorthand for: */
/* max(minimum, min(preferred, maximum)) */
:root {
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
--text-xl: clamp(1.25rem, 1rem + 1.25vw, 1.5rem);
--text-2xl: clamp(1.5rem, 1rem + 2.5vw, 2rem);
--text-3xl: clamp(1.875rem, 1rem + 4.375vw, 3rem);
--text-4xl: clamp(2.25rem, 1rem + 6.25vw, 4rem);
}
h1 {
font-size: var(--text-4xl);
}
h2 {
font-size: var(--text-3xl);
}
h3 {
font-size: var(--text-2xl);
}
p {
font-size: var(--text-base);
}
:root {
--space-xs: clamp(0.25rem, 0.2rem + 0.25vw, 0.5rem);
--space-sm: clamp(0.5rem, 0.4rem + 0.5vw, 0.75rem);
--space-md: clamp(1rem, 0.8rem + 1vw, 1.5rem);
--space-lg: clamp(1.5rem, 1rem + 2.5vw, 3rem);
--space-xl: clamp(2rem, 1rem + 5vw, 5rem);
}
.section {
padding-block: var(--space-xl);
padding-inline: var(--space-md);
}
.card {
padding: var(--space-md);
gap: var(--space-sm);
}
.container {
width: min(100% - 2rem, 1200px);
margin-inline: auto;
}
/* With fluid padding */
.container {
width: 100%;
max-width: 1200px;
margin-inline: auto;
padding-inline: clamp(1rem, 5vw, 3rem);
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
gap: clamp(1rem, 3vw, 2rem);
}
.hero {
min-height: clamp(400px, 60vh, 800px);
padding: clamp(2rem, 8vw, 6rem);
}
.hero-title {
font-size: clamp(2rem, 5vw + 1rem, 5rem);
line-height: 1.1;
}
.hero-subtitle {
font-size: clamp(1rem, 2vw + 0.5rem, 1.5rem);
max-width: clamp(300px, 60%, 600px);
}
.hero-image {
width: clamp(200px, 50%, 400px);
height: auto;
}
.icon {
width: clamp(24px, 3vw, 48px);
height: clamp(24px, 3vw, 48px);
}
.prose {
/* Optimal reading line length: 45-75 characters */
max-width: clamp(45ch, 100%, 75ch);
}
article p {
max-width: 65ch;
font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
line-height: clamp(1.5, 1.4 + 0.5vw, 1.8);
}

Supported in all modern browsers. See caniuse.com/css-math-functions.

  • Calculated at layout time, very efficient
  • No JavaScript required
  • Reduces CSS file size (fewer breakpoints)
  • Values are computed once per layout

Use clamp() when:

  • Creating fluid typography systems
  • Building responsive spacing scales
  • Setting flexible widths with constraints
  • Eliminating unnecessary media queries
  • Building design systems with consistent scaling

Use breakpoints when:

  • Layout structure needs to change (not just sizes)
  • Specific sizes needed at specific viewports
  • Component behavior changes at breakpoints
  • Design requires distinct “steps” not smooth scaling