⚡IntermediateResponsive Design

CSS clamp() and Responsive Units

Create fluid, responsive layouts without media queries using clamp(), min(), max(), and viewport units vw, vh, dvh.

Overview

Modern CSS provides fluid sizing functions that automatically scale between a minimum and maximum value as the viewport changes no breakpoints needed. **clamp(min, preferred, max)** is the most powerful: it clamps a preferred value between a lower and upper bound: - When the viewport is small → uses the minimum - When the viewport is large → uses the maximum - In between → the preferred value scales fluidly **Viewport units:** - `vw` 1% of the viewport width - `vh` 1% of the viewport height - `dvh` 1% of the dynamic viewport height (accounts for mobile browser chrome) - `vmin` / `vmax` 1% of the smaller/larger viewport dimension **CSS math functions:** - `min(a, b)` returns the smaller of the two values - `max(a, b)` returns the larger of the two values

Key Points

  • •clamp(min, preferred, max) fluid sizing in one declaration no media queries needed
  • •clamp(1rem, 2.5vw, 1.5rem) for fluid typography that scales with viewport width
  • •vw: 1% of viewport width; vh: 1% of viewport height
  • •dvh (dynamic viewport height) fixes the mobile browser address-bar issue with 100vh
  • •min(100%, 600px) is equivalent to max-width: 600px with width: 100%
  • •max(1rem, 5%) returns the larger value useful for minimum spacing
  • •clamp values can use calc() inside: clamp(1rem, calc(1rem + 2vw), 2.5rem)

Examples

Fluid typography with clamp()

/* Font size scales from 1rem (mobile) to 3rem (desktop) */
h1 {
  font-size: clamp(1.5rem, 5vw, 3rem);
}

/* Body text: stays comfortable on all screen sizes */
body {
  font-size: clamp(0.9375rem, 2vw, 1.125rem);
}

/* Subheading */
h2 {
  font-size: clamp(1.25rem, 3.5vw, 2rem);
}

clamp() eliminates the need for separate font-size media query breakpoints.

Full-height sections with dvh

/* 100vh can be taller than the visible area on mobile browsers */
.hero-old {
  min-height: 100vh; /* buggy on iOS Safari */
}

/* dvh: "dynamic" viewport height accounts for mobile browser chrome */
.hero {
  min-height: 100dvh; /* always the visible height */
}

Use dvh for full-screen sections it correctly excludes the mobile browser address bar.

min() as a max-width shortcut

.container {
  /* Equivalent to: width: 100%; max-width: 1200px; margin: 0 auto; */
  width: min(100%, 1200px);
  margin-inline: auto;
  padding-inline: clamp(16px, 5vw, 48px);
}

.sidebar {
  /* Never more than 320px, but shrinks on small screens */
  width: min(320px, 30vw);
}

min(100%, 1200px) means "never wider than 100% of the parent or 1200px" a fluid container in one line.

Common Mistakes

  • Using 100vh for full-screen mobile sections the iOS Safari address bar clips the bottom; use 100dvh instead
  • Forgetting spaces around operators in calc() inside clamp: clamp(1rem, calc(1rem+2vw), 2rem) is invalid
  • Setting vw units without accounting for scrollbar width causing horizontal overflow

Note

For fluid spacing, use clamp() on padding and gap too: padding: clamp(16px, 5vw, 48px). This creates breathing room that scales naturally from mobile to desktop without a single breakpoint.

Exercises

Write CSS to style the HTML scaffold. The preview updates live — when it looks right, mark as done.

Loading editor…

Completed: 0 / 5 exercises

Knowledge Check

Question 1 of 4

What does clamp(1rem, 3vw, 2rem) produce at a 600px viewport width?