CPCODELAB
CSS

Fluid Typography with clamp(), min(), and max()

9 min read

Sizing That Scales Smoothly Between Breakpoints

clamp(MIN, PREFERRED, MAX) constrains a value between a minimum and maximum while allowing it to respond fluidly to the viewport. Combined with viewport units as the preferred value, it produces font sizes that grow continuously — no discrete breakpoints needed.

css
/* clamp(minimum, preferred, maximum) */

/* H1: never below 1.75rem, never above 4rem,
   grows linearly between 320px and 1280px viewports */
h1 {
  font-size: clamp(1.75rem, 4vw + 1rem, 4rem);
}

/* Body: stays between 1rem and 1.25rem */
p {
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.25rem);
}

/* Container max-width with responsive padding */
.container {
  width: min(90%, 1200px);
  margin: 0 auto;
}

min() and max() in practice

min(A, B) picks the smaller value; max(A, B) picks the larger. They are like Math.min and Math.max in JavaScript and accept any mix of units.

css
/* Never wider than 600px, but shrinks on small screens */
.modal {
  width: min(600px, 90vw);
}

/* Never narrower than 300px */
.card {
  width: max(300px, 30%);
}

/* Fluid spacing: at least 1rem, but up to 4vw */
.section {
  padding-block: clamp(1rem, 4vw, 4rem);
}

/* Responsive gap without media queries */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
  gap: clamp(0.75rem, 2vw, 1.5rem);
}

Deriving fluid scales with a formula

The preferred value inside clamp() for fluid type follows the formula SLOPE * 100vw + INTERCEPT. You can compute slope as (MAX_SIZE - MIN_SIZE) / (MAX_VP - MIN_VP) and solve for intercept algebraically — or use a fluid type generator tool and copy the output.

Replace every fixed font-size in your design system with a clamp() value. The result is a layout that looks intentional at every viewport width, not just at your chosen breakpoints.

Ready to test yourself?
Practice CSS— quiz & coding exercises