Complete CSS Course Module 13: Advanced: CSS Variables and Modern Functions

CSS calc(), min(), max() and clamp()

  • Beginner
  • Lesson 13.2
  • 4 min read
  • 58 of 77 in the course

In short

CSS calc(), min(), max() and clamp() let you do math in CSS. Use them to mix units, set limits and build fluid typography that grows with the screen. How does calc() work in CSS? calc() does simple math: add, subtract, multiply and divide.

CSS calc(), min(), max() and clamp() let you do math in CSS. Use them to mix units, set limits and build fluid typography that grows with the screen.

How does calc() work in CSS?

calc() does simple math: add, subtract, multiply and divide. Its superpower is that it can mix different units, like percentages and pixels, which you cannot do by hand.

.sidebar {
  width: 250px;
}

.main {
  width: calc(100% - 250px);
}

.hero {
  min-height: calc(100vh - 80px); /* full screen minus an 80px header */
}

.box {
  padding: calc(var(--space, 1rem) * 2);
}

The .main area takes all the space except the 250px sidebar. The hero fills the screen but leaves room for the header. The last rule doubles a variable, which is a common way to build spacing steps from one base value.

Common mistake: You must put spaces around + and -. calc(100% - 20px) works, but calc(100%-20px) does not. Spaces around * and / are optional, but add them anyway for clarity.

What do min() and max() do?

min() takes a list of values and uses the smallest one. max() uses the largest one. They choose the value again every time the screen size changes.

That can feel backwards at first, so here is a simple way to remember it:

  • min() sets a maximum limit. "Be this wide, but never more than that."
  • max() sets a minimum limit. "Be this big, but never less than that."
.article {
  width: min(90%, 700px);
  margin-inline: auto;
}

.section {
  padding: max(2rem, 5vw);
}

On a phone, 90% is smaller than 700px, so the article is 90% wide. On a big screen, 700px is smaller, so the article stops at 700px. This one line replaces width: 90% plus max-width: 700px. The section padding grows with the screen width but never drops below 2rem.

Fluid typography with clamp()

clamp() takes three values: a minimum, a preferred value and a maximum.

clamp(MIN, PREFERRED, MAX)

The browser uses the preferred value, but never goes below the minimum or above the maximum. It is like a thermostat with a lowest and highest setting.

This is perfect for fluid typography: text that grows smoothly with the screen instead of jumping at breakpoints.

<header class="page-hero">
  <h1>Learn to code, one step at a time</h1>
  <p>Free lessons for complete beginners.</p>
</header>
.page-hero h1 {
  font-size: clamp(1.75rem, 1rem + 4vw, 3.5rem);
  line-height: 1.15;
}

.page-hero p {
  font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
}

Resize the browser window and watch the heading. On a small phone it stays at 1.75rem. As the window gets wider it grows smoothly, and on a large screen it stops at 3.5rem.

Tip: Always mix a rem value into the preferred value, like 1rem + 4vw, instead of using 4vw alone. Pure vw text does not get bigger when the user zooms in, which is bad for accessibility.

Responsive spacing without media queries

You can use the same tools for spacing, gaps and widths. Together with Grid, they can make a layout responsive with no media queries at all.

:root {
  --space-s: clamp(0.75rem, 0.6rem + 0.75vw, 1.25rem);
  --space-l: clamp(1.5rem, 1rem + 2.5vw, 4rem);
}

.features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr));
  gap: var(--space-s);
  padding: var(--space-l);
}

The padding and gap grow on bigger screens and shrink on phones. The min(100%, 250px) trick stops a card from being wider than its container on very small screens, so you never get a horizontal scrollbar.

FunctionWhat it returnsTypical use
calc()The result of a math sumMixing units, like 100% - 250px
min()The smallest valueA maximum width
max()The largest valueA minimum padding
clamp()A value between a min and maxFluid font sizes and spacing

Practice exercise

Build a simple blog post page. Make the content column min(92%, 65ch) wide and centered. Give the <h1> a fluid size with clamp() that goes from 2rem to 3rem. Then make the page padding responsive with clamp() too.

Hint: 65ch is about 65 characters wide, a comfortable line length for reading. Use margin-inline: auto to center the column.

Key takeaways

  • calc() does math and can mix units like %, px, rem and vh.
  • min() picks the smallest value, so it works as a maximum limit.
  • max() picks the largest value, so it works as a minimum limit.
  • clamp(min, preferred, max) is ideal for fluid typography and spacing.
  • Mix rem with vw in fluid sizes so text still responds to zoom.