Menu

CSS calc():混合单位、语法规则与示例

calc() 让你在 CSS 中做数学运算并混合使用不同单位,比如 100% 减去一个固定 200px 宽的侧边栏。学习它的语法规则(空格很重要)、calc() 配合 CSS 变量、它能解决的常见布局问题,以及为什么无效的 calc() 会被悄悄忽略。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

calc() 的作用

calc() 在 CSS 值中进行算术运算,而且可以混合使用那些只有在布局时才确定大小的单位。最经典的场景是“全部宽度减去一个固定宽度的侧边栏”:

100% 只有在页面完成布局后才能确定,而 180px 是固定的,所以没有任何一种单位能单独表达这个值。calc() 会把它算出来:在 800px 宽的预览中,这一行宽 784px,主栏得到 604px,布局下方的那一行会打印出真实的数字。如今用 flexbox 或 grid 可以不做数学运算就实现这种布局,但同样的减法仍然随处可见:高度减去头部、宽度减去间距。

语法规则

width: calc(100% - 2rem);          /* + and - need spaces on both sides */
width: calc(100% / 3);             /* divide by a plain number */
margin: calc(var(--space) * 2);    /* multiply by a plain number */
height: calc(100vh - (64px + 1rem)); /* parentheses group */
规则有效无效
+ 和 - 两侧要有空格calc(100% - 20px)calc(100%-20px)
*:至少一侧是纯数字calc(2 * 1rem)calc(2px * 3px)
/:长度除以纯数字calc(100% / 3)width: calc(300px / 3px)(结果不是长度)
单位必须兼容calc(1rem + 10px)calc(1rem + 2s)

之所以有空格规则,是因为 100% -20px 会被解读为两个独立的值,第二个是负数。当 calc() 无效时,整条声明都会被丢弃,元素保留之前规则给它的值。

试一试表达式

为盒子的宽度输入任意表达式。浏览器会告诉你它是否有效,以及最终解析出的宽度:

试试 100%-200px(无效,没有空格)、100% / 3、50% + 4rem、2 * 120px、200px * 2px(无效)和 (100% - 40px) / 2。

calc() 配合 CSS 变量

变量和 calc() 是天生的搭档:只存储一次基础值,其他值都从它推导出来。没有单位的变量乘以一个单位后,就变成了长度:

把 --space 改成 12px,或者把 --cols 改成 4,所有推导出的值都会跟着变。如何声明变量以及变量的作用域,见 CSS 变量页面。

常见用法

需求calc()
填满固定宽度元素旁边的空间width: calc(100% - 240px)
固定头部下方的区域min-height: calc(100vh - 64px)
一半宽度减去一半间距width: calc(50% - 8px)
让一个 100px 的绝对定位盒子居中left: calc(50% - 50px)
随屏幕略微变大的字号font-size: calc(1rem + 0.5vw)
把数字变量变成长度calc(var(--n) * 1px)
取变量的负值calc(var(--space) * -1)

如果一个值必须保持在某个范围内,请使用 clamp(),它的参数里可以直接写同样的运算,不用再写 calc()。

calc() 可以用在哪里

凡是允许使用长度、百分比、数字、角度或时间的地方都可以:width、margin、padding、top、font-size、line-height、网格轨道尺寸、transition-delay,以及 transform 中的角度。它可以嵌套,嵌套的 calc() 和普通的括号作用相同。

角度就是一个很好的例子。下面每个刻度都有自己的 --i(0 到 11),一条规则就能用 calc(var(--i) * 30deg) 把它变成角度:

第 3 个刻度得到 rotate(90deg),Chrome 把它报告为矩阵 matrix(0, 1, -1, 0, 0, 0):也就是旋转四分之一圈。left: calc(50% - 2px) 减去刻度自身 4px 宽度的一半,让每个刻度居中。

常见错误

  • - 或 + 两侧没有空格。 calc(100%-20px) 无效,会被忽略。
  • 两个长度相乘。 calc(10px * 2px) 在 CSS 中没有意义。* 的一侧必须是纯数字。
  • 父元素没有设置高度时,用 calc() 计算百分比高度。 和 height: 100% 一样,height 使用 calc(100% - 20px) 时需要父元素有确定的高度。
  • 在 flexbox 或 grid 就能搞定的地方使用 calc()。 用 width: calc(33.333% - 10px) 来做分栏很脆弱;display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px 则完全不需要计算。
  • 以为会看到错误信息。 浏览器不会对无效的 calc() 发出警告。请在开发者工具中检查元素:无效的声明会显示为被划掉的样子。

常见问题

CSS 中的 calc() 有什么作用?

它根据包含 +、-、* 和 / 的表达式计算出一个值,并且可以混合使用只有在布局时浏览器才知道具体大小的单位。width: calc(100% - 200px) 表示父元素的全部宽度减去 200px,不管父元素有多宽。

为什么我的 calc() 不生效?

最常见的原因是缺少空格:+ 和 - 两侧必须有空白,所以 calc(100%-20px) 是无效的。其他原因还有:两个长度相乘(10px * 2px),或者除以一个长度,这样得到的都不是长度。无效的 calc() 会让整条声明失效,于是浏览器会忽略它。

calc() 中可以使用 CSS 变量吗?

可以。calc(var(--gap) * 2) 把变量翻倍,calc(var(--columns) * 1px) 把一个没有单位的数字变成像素值。浏览器会先代入变量的值,再进行计算。

calc() 中的 * 和 / 两侧需要空格吗?

不需要。只有 + 和 - 要求有空格,因为没有空格的话,-20px 会被当成一个负数。* 和 / 两侧的空格可有可无,但所有运算符两侧都加空格是最容易记住的规则。

calc() 和 clamp() 有什么区别?

calc() 根据一个表达式计算出一个值。clamp(MIN, VAL, MAX) 把一个值限制在两个界限之间。两者可以组合使用:clamp() 的每个参数本身就可以包含 calc 风格的运算,比如 clamp(1rem, 1rem + 2vw, 3rem)。

Coddy 编程语言插图

和 Coddy 一起学编程

开始