CSS calc()的完整指南

CSS具有calc()执行基本数学运算的特殊功能。

.main-content {
  /* 从100vh减去80px */
  height: calc(100vh - 80px);
}

在本指南中,我将介绍有关此非常有用的功能的所有知识。 推荐阅读之前写过一篇类似文章《css3 calc()属性介绍以及自适应布局使用方法》。

calc()用于值

可以使用calc()函数的唯一地方是值。请看下面这些示例,其中我们为许多不同的属性设置值。

.el {
  font-size: calc(3vw + 2px);
  width:     calc(100% - 20px);
  height:    calc(100vh - 20px);
  padding:   calc(1vw + 5px);
}

它也可以仅用于属性的一部分,例如:

.el {
  margin: 10px calc(2vw + 5px);
  border-radius: 15px calc(15px / 3) 4px 2px;
  transition: transform calc(1s - 120ms);
}

它甚至可以成为构成属性一部分的另一个函数的一部分!例如,在颜色渐变属性中使用calc():

.el {
  background: #1E88E5 linear-gradient(
    to bottom,
    #1E88E5,
    #1E88E5 calc(50% - 10px),
    #3949AB calc(50% + 10px),
    #3949AB
  );
}

calc()用于长度和其他数字事物

请注意,以上所有示例本质上都是基于数字的。我们将讨论一些数字使用方法的注意事项(因为有时不需要单位),但这是用于数字数学的,而不是字符串或类似的东西。

.el {
  /* 不可以! */
  counter-reset: calc("My " + "counter");
}
.el::before {
  /* 不可以! */
  content: calc("Candyman " * 3);
}

CSS有很多长度,它们都可以用于calc():

  • px
  • %
  • em
  • rem
  • in
  • mm
  • cm
  • pt
  • pc
  • ex
  • ch
  • vh
  • vw
  • vmin
  • vmax

当然没有单位数也可以接受,例如line-height: calc(1.2 * 1.2);,如transform: rotate(calc(10deg * 5));

当我们不用calc()去执行任何计算时,它仍然有效:

.el {
  /* 有点怪,不过还好 */
  width: calc(20px);
}

不接受媒体查询

如果calc()使用正确(将长度单位用作属性的值),则将其calc()应用于媒体查询时无法使用。

@media (max-width: 40rem) {}

/* 不可以 */
@media (min-width: calc(40rem + 1px)) {}

混合单元

这也许是最能体现calc()价值的功能!上面几乎每个示例都已经做到了这一点,但只是要指出一点,这里混合了不同的长度单元:

width: calc(100% - 20px);

这就是说:元素的宽度为负20像素。

有字面上没有办法预先计算出在流体宽度的情况下单独的像素值。换句话说,calc()无法使用Sass之类的东西进行预处理,以尝试完成polyfill。不需要,因为浏览器支持很好。但是要点是,当我们以这种方式混合单位时,必须在浏览器中(“运行时”)完成操作,这是的大部分值calc()。

这是混合单元的其他一些示例:

transform: rotate(calc(1turn + 45deg));

animation-delay: calc(1s + 15ms);

这些可能会被预处理,因为它们混合了与运行时确定的任何单位都不相关的单位。

与预处理器数学比较

我们刚刚介绍了无法预处理calc()可以做的最有用的事情。但是有一点需要注意,例如,Sass内置了数学功能,因此可以执行以下操作:

$padding: 1rem;

.el[data-padding="extra"] {
  padding: $padding + 2rem; 
  margin-bottom: $padding * 2; 
}

甚至带有单位的数学也可以在这里工作,将相同单位的值相加或乘以无单位数。但是你不能混合使用单位,并且它也有类似的限制calc()(例如,乘法和除法必须使用无单位的数字)。

数学计算

例如,通过calc()假设你需要计算准确1 / 7个元素的宽度

.el {
  /* 这更容易理解 */
  width: calc(100% / 7);

  /* 传统的写法 */
  width: 14.2857142857%;
}

这可能会在某种自行创建的CSS API中获得成功,例如:

[data-columns="7"] .col { width: calc(100% / 7); }
[data-columns="6"] .col { width: calc(100% / 6); }
[data-columns="5"] .col { width: calc(100% / 5); }
[data-columns="4"] .col { width: calc(100% / 4); }
[data-columns="3"] .col { width: calc(100% / 3); }
[data-columns="2"] .col { width: calc(100% / 2); }

calc()的数学运算符

数学运算符+,-,*,和/ 对于大家来说并不陌生。但是这里在使用它们的方式上有所不同。

加号(+)和减号(-)要求两个数字均为长度

.el {
  /* 有效 👍 */
  margin: calc(10px + 10px);

  /* 无效 👎 */
  margin: calc(10px + 5);
}

无效的值会使整个单独的声明无效。

除(/)要求第二个数字不能为无单位

.el {
  /* 有效👍 */
  margin: calc(30px / 3);

  /* 无效 👎 */
  margin: calc(30px / 10px);

  /* 无效👎 (不能除以0) */
  margin: calc(30px / 0);
}

乘法(*)要求数字之一为无单位

.el {
  /* 有效👍 */
  margin: calc(10px * 3);

  /* 有效 👍 */
  margin: calc(3 * 10px);

  /* 无效 👎 */
  margin: calc(30px * 3px);
}

空格很重要

可以进行加法和减法。

.el {
  /* 有效👍 */
  font-size: calc(3vw + 2px);

  /* 无效 👎 */
  font-size: calc(3vw+2px);

  /* 有效 👍 */
  font-size: calc(3vw - 2px);

  /* 无效 👎 */
  font-size: calc(3vw-2px);
}

负数是可以的(例如calc(5vw - - 5px)),但这是一个例子,说明空白不仅是必需的,而且是有用的。

之所以需要在+和-之间设置间距,实际上是因为解析问题。例如,2px-3px被解析为数字“2”和单位“px-3px”,+还有其他问题,比如“被数字语法占用了”。我猜空白应该与自定义属性的- -语法有关,但不是!

乘法和除法不需要运算符周围的空格。但是我个人建议为了可读性还是有必要加上

外部的空白无关紧要。我们甚至可以根据需要进行换行:

.el {
  /* Valid 👍 */
  width: calc(
    100%     /   3
  );
}

但是请注意这一点:calc和()括号之间没有空格。

.el {
  /* 无效👎 */
  width: calc (100% / 3);
}

嵌套calc(calc())

.el {
  width: calc(
    calc(100% / 3)
    -
    calc(1rem * 2)
  );
}

calc()里面嵌套的calc()是可以忽略掉的,因为它的父级是单独工作的:

.el {
  width: calc(
   (100% / 3)
    -
   (1rem * 2)
  );
}

在这种情况下,即使没有括号,也会遵循数学中的加减乘除的“操作顺序”规则。也就是说,除法和乘法首先发生(在加法和减法之前),因此根本不需要括号。可以这样写:

.el {
  width: calc(100% / 3 - 1rem * 2);
}

如果我们确实需要先进行加法或减法,则需要给它们加上必要的括号就可以啦。

.el {
  width: calc(100% + 2rem / 2);

  width: calc((100% + 2rem) / 2);
}

CSS自定义属性和calc()使用

除了calc()混合单元的惊人功能外,接下来最令人惊讶的是calc()可将其与自定义属性一起使用。自定义属性可以在随后的计算中使用:

html {
  --spacing: 10px;
}

.module {
  padding: calc(var(--spacing) * 2);
}

我敢肯定,你可以想象一个CSS设置,其中设置一堆CSS自定义属性,然后让其余的CSS根据需要使用它们,从而在顶部进行大量配置。

自定义属性也可以相互引用。下面是一个例子,其中使用了一些数学(注意,首先缺少calc()函数),然后再应用。(它最终必须在calc()中。)

html {
  --spacing: 10px;
  --spacing-L: var(--spacing) * 2;
  --spacing-XL: var(--spacing) * 3;
}

.module[data-spacing="XL"] {
  padding: calc(var(--spacing-XL));
}

你可能不喜欢这样,因为你需要记住calc()在哪里使用该属性,但从可读性的角度来看,这是可能的,而且可能很有趣。

自定义属性可以来自HTML,这有时是一件非常酷和有用的事情。

<div style="--index: 1;"> ... </div>
<div style="--index: 2;"> ... </div>
<div style="--index: 3;"> ... </div>
div {
  /* 索引值来自HTML(带有回退) */
  animation-delay: calc(var(--index, 1) * 0.2s);
}

添加单位

如果你处于这样一种情况:没有单位的数字更容易存储,或者提前用没有单位的数字进行数学运算,你可以一直等到你应用数字乘以1和单位来添加单位。

html {
  --importantNumber: 2;
}

.el {
  /* Number stays 2, but it has a unit now */
  padding: calc(var(--importantNumber) * 1rem);
}

色彩值的使用

像RGB和HSL这样的颜色格式有可以使用calc()处理的数字。例如,设置一些基本HSL值,然后更改它们以形成自己创建的系统(示例):

html {
  --H: 100;
  --S: 100%;
  --L: 50%;
}

.el {
  background: hsl(
    calc(var(--H) + 20),
    calc(var(--S) - 10%),
    calc(var(--L) + 30%)
  )
}

不能将calc()和attr()合并

CSS中的attr()函数看起来很吸引人,就像你可以从HTML中提取属性值并使用它们一样。但是

<div data-color="red">...</div>

div {
 /* 不行 */
 color: attr(data-color);
}

这里没有“类型”,所以attr()的唯一用途是与content属性一起使用的字符串。这意味着这样是有效的:

div::before {
  content: attr(data-color);
}

我之所以提到这一点,是因为试图以这种方式提取一个数字以用于计算可能会很有诱惑力,例如:

<div class="grid" data-columns="7" data-gap="2">...</div>
.grid {
  display: grid;

  /* 这两项工作都没有 */
  grid-template-columns: repeat(attr(data-columns), 1fr);
  grid-gap: calc(1rem * attr(data-gap));
}

幸运的是,这并不重要,因为HTML中的自定义属性同样有用甚至更多!

<div class="grid" style="--columns: 7; --gap: 2rem;">...</div>
.grid {
  display: grid;

  /* 好了! */
  grid-template-columns: repeat(var(--columns), 1fr);
  grid-gap: calc(var(--gap));
}

浏览器工具

浏览器开发工具会倾向于在样式表中编写calc()时向你显示它。

浏览器工具

如果需要计算出的值,可以使用“计算”​​选项卡(在所有浏览器的DevTools中,至少是我所知道的)向你显示。

Chrome DevTools –计算

浏览器支持

该浏览器支持数据来自Caniuse,它具有更多详细信息。数字表示浏览器支持该版本及更高版本的功能。

浏览器支持

如果确实需要支持更早版本(例如IE 8或Firefox 3.6),通常的技巧是在使用calc()以下属性或值之前添加另一个属性或值:

.el {
  width: 92%; /* Fallback */
  width: calc(100% - 2rem);
}

当然也有很多已知的问题calc(),不过它们都是针对旧浏览器的。

  • Firefox <59不支持 calc() 颜色功能。范例: color: hsl(calc(60 * 2), 100%, 50%)。
  • 当IE 9 – 11 用于任何值box-shadow 时,将不会呈现该 属性 calc()。
  • width: calc() 用在表格单元格上时,在IE 9-11和Edge都不支持

如果要将calc()用作包含视口单位等的流体类型情况下,请确保包含使用rem或em的单位,以便用户仍然可以根据需要通过放大或缩小来控制字体的上下起伏。

1. 本站所有免费资源来源于用户上传和网络,因此不包含技术服务请大家谅解!如有侵权请邮件联系客服!
2. 本站不保证所提供下载的免费资源的准确性、安全性和完整性,免费资源仅供下载学习之用!如有链接无法下载、失效,请联系客服处理!
3. 您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容资源!如用于商业或者非法用途,与本站无关,一切后果请用户自负!
4. 如果您也有好的资源或技术教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
5. 加入前端开发QQ群:565733884,我们大家一起来交流技术!
码云笔记 » CSS calc()的完整指南

发表评论