Home/Learn/HTML, CSS & Responsive/Fluid Type and Spacing

Fluid Type and Spacing

Advanced
Responsive

Scaling type and space continuously with clamp() replaces most sizing breakpoints and removes the jumps where a heading changes size mid-drag.

Overview

Breakpoint-based sizing produces layouts that are correct at four widths and awkward between them: a heading at 32px until 768px and then suddenly 48px. Fluid sizing interpolates instead, so the value tracks the viewport smoothly and is right everywhere. clamp() expresses this in one declaration with a floor and a ceiling. The accessibility caveat matters and is widely missed — a preferred value expressed purely in vw stops responding to the user's font size, so a rem term has to be part of the formula.

Fluid Type

clamp() with a mixed rem and vw preferred value.

Always mix rem into the preferred value
/* clamp(minimum, preferred, maximum) */
h1 { font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem) }
p  { font-size: clamp(1rem, 0.95rem + 0.25vw, 1.125rem) }

/* Why the preferred value is a SUM:
     clamp(2rem, 5vw, 3.5rem)          — pure vw: a user who doubles
                                          their browser font size sees
                                          no change at all
     clamp(2rem, 1.5rem + 2.5vw, 3.5rem) — the rem term keeps it
                                          responsive to that setting  */

/* Deriving the numbers: to go from 2rem at 320px to 3.5rem at 1280px
     slope = (3.5 - 2) / (1280 - 320) * 100vw  = 0.156vw per px = 15.6vw... */
/* In practice use a generator (utopia.fyi) rather than the algebra,
   and check both ends in the browser. */

/* A fluid scale, defined once as tokens */
:root {
  --step--1: clamp(0.83rem, 0.8rem + 0.15vw, 0.94rem);
  --step-0:  clamp(1rem,    0.96rem + 0.2vw, 1.13rem);
  --step-1:  clamp(1.2rem,  1.14rem + 0.3vw, 1.41rem);
  --step-2:  clamp(1.44rem, 1.35rem + 0.45vw, 1.76rem);
}
h2 { font-size: var(--step-2) }

Fluid Space

The same technique for padding and gaps, where it matters more than people expect.

Fluid space tokens, and the wrapper idiom
:root {
  --space-s:  clamp(0.75rem, 0.7rem + 0.25vw, 1rem);
  --space-m:  clamp(1rem, 0.9rem + 0.5vw, 1.5rem);
  --space-l:  clamp(2rem, 1.6rem + 2vw, 4rem);
  --space-xl: clamp(4rem, 3rem + 5vw, 8rem);
}

.section { padding-block: var(--space-xl) }
.card { padding: var(--space-m); gap: var(--space-s) }

/* Generous section padding on a desktop looks absurd on a phone,
   and phone padding looks cramped on a desktop. Fluid space fixes
   both without a single media query. */

/* The content wrapper — the pattern almost every page needs */
.wrapper {
  width: min(100% - 2rem, 72rem);
  margin-inline: auto;
}
/* Reads as: full width minus a 1rem gutter each side, capped at
   72rem, centred. One declaration replaces width + max-width +
   padding + box-sizing. */

Intrinsic Layouts

Letting the content decide, so there is nothing left to query.

Constraints instead of breakpoints
/* A grid that reflows with no breakpoints at all */
.cards { display: grid; gap: var(--space-m);
         grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr)) }

/* A sidebar that becomes a stack when there is not enough room */
.with-sidebar { display: flex; flex-wrap: wrap; gap: var(--space-m) }
.with-sidebar > .side { flex: 1 1 15rem }
.with-sidebar > .main { flex: 999 1 30rem }
/* The huge flex-grow on main means it takes all the space when both
   fit; when main cannot reach its 30rem basis, the row wraps and
   they stack. No media query, and it responds to the CONTAINER. */

/* Text that never gets too wide to read */
.prose { max-width: 65ch }

/* The principle: describe the constraints and let the browser solve
   the layout. Media queries are then for genuine structural changes
   — a nav becoming a drawer — rather than for sizing. */

Key Points to Remember

  • 1clamp() interpolates a value continuously, removing the jumps that breakpoint-based sizing produces
  • 2A preferred value in vw alone ignores the user's font-size setting — always include a rem term
  • 3Fluid spacing tokens fix both cramped phone padding and absurd desktop padding without media queries
  • 4width: min(100% - 2rem, 72rem) with margin-inline: auto is the complete content wrapper in two lines
  • 5Intrinsic patterns like auto-fit grids and flex-basis wrapping respond to the container, leaving media queries for real structural changes

Interview Questions

Sign in to ask Aria
1

What does clamp() do and why is it useful for typography?

Medium
2

Why is a font-size of clamp(2rem, 5vw, 3rem) an accessibility problem?

Hard
3

How can a sidebar layout collapse to a stack without any media query?

Hard

Ask Aria about Fluid Type and Spacing

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…