Loading...

CSS Calc and Math Functions

Custom properties gave you named values. Math functions let those values (and plain lengths) compute at render time: subtract a sidebar from 100%, cap a column with min(), or grow type smoothly with clamp() — no Sass build step required.

calc() — arithmetic in property values

Wrap an expression in calc(...). The browser evaluates it when computing the property. Plus and minus need spaces around the operator; * and / can be tighter but stay readable:

Main column beside a fixed sidebar

css
:root {
--sidebar-w: 16rem;
--gap: 1rem;
}

.layout {
display: flex;
gap: var(--gap);
}

.sidebar {
flex: 0 0 var(--sidebar-w);
}

.main {
flex: 1 1 auto;
min-width: 0;
/* readable fallback when flex alone is not enough */
max-width: calc(100% - var(--sidebar-w) - var(--gap));
}

Here calc() expresses “remaining width” explicitly — useful in grids, absolute positioning, or when a parent is not flex. You can mix %, rem, px, vw, and var(--tokens) as long as the result is valid for that property.

Spaces and unit rules (calc gotchas)

Invalid: calc(100%-2rem) — the parser needs space before -. Valid: calc(100% - 2rem). Multiplication requires at least one number factor: calc(var(--space) * 2) works; calc(2rem * 3rem) does not.

Padding from a spacing token

css
.card {
--space: 0.75rem;
padding: var(--space) calc(var(--space) * 2);
margin-block: calc(var(--space) / 2);
}

calc() runs at computed-value time, so it sees the resolved var(--space). That pairs naturally with the variables lesson — tokens supply numbers, math functions transform them into layout.

min() and max() — pick an extreme

Both accept a comma-separated list of lengths. min() returns the smallest; max() the largest. Handy for responsive caps without a media query for every breakpoint:

Column that never overflows the viewport

css
.hero-inner {
width: min(100% - 2rem, 72rem);
margin-inline: auto;
}

.feature-grid {
grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}

min(100% - 2rem, 72rem) means “full width minus gutters, but never wider than 72rem”. minmax(...) inside grid is a common pairing — the inner min() avoids overflow on narrow screens.

clamp() — bounded fluid values

clamp(MIN, PREFERRED, MAX) is shorthand for “at least MIN, at most MAX, otherwise PREFERRED”. Order matters: minimum first, maximum last. Perfect for fluid type and fluid spacing:

Fluid heading between readable bounds

css
:root {
--text-base: clamp(1rem, 0.95rem + 0.35vw, 1.125rem);
--heading-lg: clamp(1.75rem, 1.2rem + 2vw, 2.75rem);
}

body {
font-size: var(--text-base);
}

h1 {
font-size: var(--heading-lg);
line-height: 1.2;
}

The middle term often mixes rem + vw so size grows with viewport but stops at the caps. You can nest clamp() inside var() on :root — one token update retunes the whole scale.

Which function when?

📊 Math functions at a glance

Function Think of it as Typical use
calc() Spreadsheet cell for one property Subtract gutters, add offsets, double a token with * 2
min() “No larger than…” among choices Cap width, pick narrower of % and px
max() “At least this big…” Floor a size, ensure touch target minimum
clamp() min + preferred + max in one Fluid font-size, fluid section padding with hard limits

You can combine them: width: min(100%, calc(var(--max-w) + 2rem)); — keep expressions readable; split into tokens on :root when a formula repeats.

Sticky footer helper with max()

When content is short, the footer should still sit at the bottom; when content grows, the block expands:

Main area at least viewport minus header

css
:root {
--header-h: 4rem;
}

.page {
min-height: max(100vh, calc(100vh - var(--header-h) + 100%));
}

/* simpler pattern most teams use */
.page-simple {
min-height: calc(100vh - var(--header-h));
display: flex;
flex-direction: column;
}

Prefer the simple pattern when it matches your layout; the lesson shows that math functions express relationships declaratively in CSS — not only in JavaScript or preprocessors.

Try it yourself

  1. Build a two-column row: fixed --sidebar-w, calc(100% - var(--sidebar-w) - gap) on the main pane.
  2. Replace a rigid font-size: 24px with clamp(1.25rem, 1rem + 1.5vw, 2rem) and resize the viewport.
  3. Use min(100%, 40rem) on a article wrapper; compare with plain width: 100%.
  4. Move a repeated formula to :root as --content-w: min(100% - 2rem, 70rem); and reuse it in three selectors.
  5. Fix calc(100%-1rem) by adding spaces; confirm DevTools no longer strikes the declaration.

Common mistakes

  • calc(100%-2rem) without spaces around - — rule fails
  • clamp(2rem, 1rem + 1vw, 1rem) with min greater than max — confusing or ignored behavior
  • Using max() when you meant a ceiling (often min() instead)
  • Putting calc(...) in a property name — only values, like var()
  • Expecting calc() to divide two lengths like calc(10rem / 2rem) — division needs a number divisor

Summary

  • calc() adds, subtracts, multiplies, and divides in values — mind spaces around + / -
  • min() / max() choose among comma-separated lengths for caps and floors
  • clamp(min, preferred, max) drives fluid typography and spacing with bounds
  • Pair math with var(--tokens) for maintainable responsive layout
  • Next in Modern Toolkit: native CSS nesting for clearer selector structure

🧠 Test Your Knowledge

Ready to Start

Test Your Knowledge

Challenge yourself with this interactive quiz and see how well you understand the topic

❓
6
Questions
🎯
70%
To Pass
♾️
∞
Time
🔄
∞
Attempts

📝 Instructions

  • Read each question carefully
  • Select the best answer for each question
  • You can retake the quiz as many times as you want
  • Your progress will be shown at the top