CSS Handbook · 自定义属性与现代函数

第十章 / 10.2 calc / min / max / clamp

第十章 · 10.2 节

calc / min / max / clamp


这一组数学函数让 CSS 具备了真正的运算能力:可以混合不同单位相减、可以在两个候选值里挑一个更合适的、也可以让一个值被限制在安全区间内。4.5 节的流式字号,正是建立在这些函数之上。

calc():混合单位运算

支持加减乘除四则运算,最大的价值在于可以混合不同单位——比如"视口宽度减去一个固定像素间距",这是单纯用百分比或 px 都无法表达的。

.sidebar-content {
  width: calc(100% - 240px);
}
.section {
  margin-top: calc(var(--gap) * 2);
}
语法细节加减号两侧必须保留空格(calc(100% - 240px) 而非 calc(100%-240px)),否则会被解析为一个非法的连字符值;乘除号两侧空格则是可选的。

min() 与 max()

接受任意多个参数,min() 取其中最小值生效,max() 取最大值——本质是把原本需要写在媒体查询里的"取较小/较大者"逻辑,压缩进一行声明。

/* 容器宽度:不超过 1200px,但小屏下让出 32px 边距 */
.container {
  width: min(1200px, 100% - 32px);
}

/* 字号:不小于 14px */
p { font-size: max(14px, 1vw); }

clamp():三值夹逼

clamp(最小值, 首选值, 最大值) 等价于 max(最小值, min(首选值, 最大值)) 的语法糖,是响应式排版中使用频率最高的函数:

h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}
三个区间的行为
视口状况实际生效值
4vw 计算结果 < 1.5rem取最小值 1.5rem
1.5rem ≤ 4vw ≤ 3rem取首选值 4vw,跟随视口连续变化
4vw 计算结果 > 3rem取最大值 3rem

函数嵌套与变量结合

这些函数可以自由嵌套,也能直接读取自定义属性,组合出复杂的自适应逻辑:

:root { --base: 16px; }

.card {
  padding: clamp(var(--base), 2vw + var(--base), calc(var(--base) * 2));
}

实战:自适应侧边栏

结合 clamp() 与 Grid,可以做出一个"侧边栏宽度随视口渐变,但有上下限"的布局,替代原本需要两三条媒体查询才能实现的效果:

.layout {
  display: grid;
  grid-template-columns: clamp(200px, 20vw, 320px) 1fr;
}

侧边栏最窄不小于 200px(避免内容挤压变形),最宽不超过 320px(避免在超宽屏上占据过多空间),中间区间跟随视口宽度的 20% 平滑变化。

Chapter 10 · Section 10.2

calc / min / max / clamp


This family of math functions gives CSS real computing power: you can mix different units in arithmetic, pick the better of two candidate values, or confine a value to a safe range. The fluid font sizing in Section 4.5 is built precisely on these functions.

calc(): Mixing Units in Arithmetic

It supports the four basic arithmetic operations. Its greatest value lies in being able to mix different units — for instance, "viewport width minus a fixed pixel gutter", which is impossible to express with percentages or px alone.

.sidebar-content {
  width: calc(100% - 240px);
}
.section {
  margin-top: calc(var(--gap) * 2);
}
Syntax detailSpaces are required around the plus and minus signs (calc(100% - 240px), not calc(100%-240px)), otherwise the expression is parsed as an invalid hyphenated value; spaces around multiplication and division are optional.

min() and max()

Both accept any number of arguments: min() applies the smallest value, max() the largest — essentially compressing the "take the smaller/larger one" logic that used to live in media queries into a single declaration.

/* container width: no more than 1200px, but leave 32px margin on small screens */
.container {
  width: min(1200px, 100% - 32px);
}

/* font size: never smaller than 14px */
p { font-size: max(14px, 1vw); }

clamp(): Three-Value Clamping

clamp(min, preferred, max) is syntactic sugar for max(min, min(preferred, max)), and it is the most frequently used function in responsive typography:

h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}
Behavior of the three ranges
Viewport conditionEffective value
4vw evaluates to < 1.5remTakes the minimum, 1.5rem
1.5rem ≤ 4vw ≤ 3remTakes the preferred 4vw, following the viewport continuously
4vw evaluates to > 3remTakes the maximum, 3rem

Nesting Functions with Custom Properties

These functions can nest freely and read custom properties directly, composing complex adaptive logic:

:root { --base: 16px; }

.card {
  padding: clamp(var(--base), 2vw + var(--base), calc(var(--base) * 2));
}

Practice: A Responsive Sidebar

Combining clamp() with Grid yields a layout whose "sidebar width glides with the viewport but has lower and upper limits", replacing what used to take two or three media queries:

.layout {
  display: grid;
  grid-template-columns: clamp(200px, 20vw, 320px) 1fr;
}

The sidebar is never narrower than 200px (so the content is not crushed), never wider than 320px (to avoid taking up too much space on very wide screens), and in between it follows 20% of the viewport width smoothly.