数学函数与流式排版
基于 CSS 现代标准 · 核于 2026-06
速查
calc(表达式):在值里做加减乘除,可混合单位(100% - 2rem);可嵌套、可配var()calc()规则:+/-两侧必须留空格;*//可单侧带单位,除数须是无单位数min(a, b, …):取最小——用来设「上限」(如min(20vw, 30rem):随视口涨但不超 30rem)max(a, b, …):取最大——用来设「下限」(如max(20vh, 20rem):随视口缩但不小于 20rem)clamp(最小, 理想, 最大):把值夹在区间里,理想值带vw即随视口平滑伸缩clamp(a, b, c)≡max(a, min(b, c))——一行顶过去好几个媒体查询断点- 流式字号经典式:
font-size: clamp(1rem, 0.5rem + 1.5vw, 1.5rem)(理想值带rem保证可缩放/可访问) - 流式宽度:
width: min(65ch, 100%)(小屏占满、大屏封顶到易读的 65 字符宽) - 这些函数能跨单位类型比较计算值;嵌套
var()让「变量 + 数学」组合出动态布局 - Baseline:
calc/min/max/clamp均广泛可用,可无脑使用
calc():在值里做运算
calc() 让你在 CSS 值里直接做数学,最大的价值是混合不同单位——这是 CSS 别处做不到的:
.my-element {
/* 百分比减去固定长度:100% 宽减掉两侧各 1rem 的留白 */
width: calc(100% - 2rem);
}它能嵌套,也能配合自定义属性:
.my-element {
width: calc(calc(10% + 2rem) * 2);
height: calc(var(--root-height) * 3);
}calc() 的运算符空格规则
+ 和 - 两侧必须各留一个空格——calc(100% -2rem) 会被误解析(-2rem 看成一个负长度而非减法),写成 calc(100% - 2rem) 才对。* 和 / 没这么严格,但除号的除数必须是无单位的数。
min() 与 max():设上限与下限
这两个函数接受多个值,分别返回其中最小和最大的那个。关键在于理解它们在响应式里的「方向」——往往和名字直觉相反:
min() —— 取小 = 设「上限」
.my-element {
/* 宽度随视口走(20vw),但永远不超过 30rem */
width: min(20vw, 30rem);
}min() 取较小值,意味着结果不会超过列表里最小的那个上界——所以它的实际效果是「封顶」:视口小的时候用 20vw,视口大到 20vw 超过 30rem 时,就被 30rem 卡住。
max() —— 取大 = 设「下限」
.my-element {
/* 高度随视口走(20vh),但永远不小于 20rem */
height: max(20vh, 20rem);
}max() 取较大值,结果不会低于列表里最大的那个下界——效果是「保底」:视口太小导致 20vh 缩得太狠时,由 20rem 兜住。
一句话记牢方向
min() 设上限(封顶),max() 设下限(保底)——名字取的是「函数返回哪个值」,而响应式效果恰好相反,这是最容易绕晕的点。
clamp():把值夹在区间里
clamp(最小值, 理想值, 最大值) 是流式排版的主角——它把一个值约束在最小和最大之间,而理想值负责在区间内平滑伸缩:
h1 {
font-size: clamp(2rem, 1rem + 3vw, 3rem);
}- 视口很窄时,
1rem + 3vw小于2rem→ 取2rem(下限); - 视口很宽时,
1rem + 3vw大于3rem→ 取3rem(上限); - 中间区段,字号随视口宽度(
vw)平滑变化。
它等价于 max(最小, min(理想, 最大)),但一行就把「下限 + 理想 + 上限」三件事说清了——一个 clamp() 顶过去好几个 @media 断点。
理想值为什么要带 rem(可访问性)
经典写法 clamp(2rem, 1rem + 3vw, 3rem) 的理想值里特意混入了 rem,而不是纯 vw。原因是:纯 vw 的字号在用户放大页面(zoom)时不会跟着变大,伤害可访问性;混入 rem 后,字号仍能响应用户的缩放设置。这是流式字号的最佳实践。
流式排版实战
把上面几个函数组合起来,就能用极少的代码做出「无媒体查询」的响应式排版。
流式字号
:root {
/* 一套流式字阶:每一级都在小屏/大屏间平滑过渡 */
--step-0: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
--step-1: clamp(1.25rem, 1rem + 1vw, 1.75rem);
--step-2: clamp(1.75rem, 1.3rem + 2vw, 2.75rem);
}
body {
font-size: var(--step-0);
}
h2 {
font-size: var(--step-2);
}流式宽度与间距
.prose {
/* 正文宽度:小屏占满,大屏封顶到 65 字符(最佳阅读宽度) */
inline-size: min(65ch, 100%);
/* 区块间距随视口微调,但夹在 1rem~3rem 之间 */
padding-block: clamp(1rem, 5vw, 3rem);
margin-inline: auto;
}配 var() 做动态布局
数学函数和自定义属性(见 自定义属性与 var())天生一对——把变量喂进 calc() / clamp(),布局就能由变量驱动:
.grid {
--min-col: 16rem;
/* 每列至少 --min-col 宽,放不下就换行——经典「自适应卡片网格」 */
grid-template-columns: repeat(auto-fill, minmax(min(var(--min-col), 100%), 1fr));
gap: clamp(0.5rem, 2vw, 1.5rem);
}单位混合与嵌套
这些函数都能跨单位类型比较 / 运算:calc() 明确允许在一个表达式里混合单位;min() / max() / clamp() 则会先把各参数求出计算值再比较——于是 min(20vw, 30rem) 这种「视口单位 vs 绝对单位」的比较才成立。它们也都能互相嵌套、并接受 var() 作为参数,组合空间很大。
Baseline 与兼容
calc()、min()、max()、clamp() 都已 Baseline 广泛可用(calc() 历史悠久;min/max/clamp 自约 2020 年起全主流浏览器支持),可放心用于生产,无需降级。
小结
CSS 的数学函数把「响应式」从「按断点切换」升级成「随视口流动」:calc() 混合单位运算,min() 设上限(封顶)、max() 设下限(保底),clamp(最小, 理想, 最大) 把值夹进区间并平滑伸缩——一行流式字号 / 宽度顶过去一堆媒体查询,配 var() 还能做变量驱动的动态布局。它们全部 Baseline 广泛可用。下一页从「单条样式的写法」上升到「整张样式表怎么组织」——组织方法论:BEM·层·@scope。