Math Functions and Fluid Sizing
Prerequisites: Custom properties, Units and values
CSS can calculate values at run time, mixing units the browser only knows during layout.
calc()
.main { width: calc(100% - 16rem); }
.hero { min-height: calc(100dvh - var(--header-height)); }
.grid { gap: calc(var(--space) * 2); }
Spaces are required around + and - (calc(100% -2rem) is
invalid; -2rem would be read as a negative number).
min(), max(), clamp()
<style>
.box { width: min(100%, 500px); }
.pad { padding: max(1rem, 5%); }
.title { font-size: clamp(1.5rem, 1rem + 3vw, 3rem); }
.narrow { width: 300px; }
.wide { width: 1200px; }
</style>
<div class="narrow"><div class="box pad"><h2 class="title">A</h2></div></div>
<div class="wide"><div class="box pad"><h2 class="title">B</h2></div></div>
<script>
for (const box of document.querySelectorAll(".box")) {
const s = getComputedStyle(box);
console.log(box.parentElement.className.padEnd(6), "width:", s.width, "padding:", s.paddingLeft,
"title:", getComputedStyle(box.querySelector(".title")).fontSize);
}
</script>
narrow width: 300px padding: 16px title: 48px
wide width: 500px padding: 60px title: 48px
min(100%, 500px)— at most 500px, but never wider than the container: 300px in the narrow one, 500px in the wide one. It replaceswidth: 100%; max-width: 500pxin one line.max(1rem, 5%)— at least 16px, or 5% of the container width if that's larger (5% of 1200px = 60px).clamp(min, preferred, max)— the preferred value, kept between the limits. Both titles computed the same size becausevwdepends on the viewport, not the container (the example ran in a 1280px-wide window: 16px + 3 × 12.8px = 54.4px, clamped to 48px).
Fluid typography
clamp() with a rem + vw middle value scales type smoothly between a
minimum and maximum, without breakpoints:
:root {
--step-0: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
--step-1: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
--step-2: clamp(1.5rem, 1.2rem + 1.4vw, 2.25rem);
--step-3: clamp(2rem, 1.4rem + 2.8vw, 3.5rem);
}
h1 { font-size: var(--step-3); }
Always include a rem part: text sized purely in vw doesn't grow when
people zoom, which fails accessibility guidelines.
More functions
round(),mod(),rem(),abs(),sign(), and trigonometric functions (sin(),cos(), ...) exist in current browsers — useful for snapping values and circular layouts.attr()reads an HTML attribute; incontentit has always worked, and newer browsers allow typed use in other properties.
Practice
Write a .container that is 90% of the viewport wide on phones, but
never wider than 72rem, centered — in one width declaration.
Show solution
.container {
width: min(90vw, 72rem);
margin-inline: auto;
}