CSS:完整的calc()功能指南

CSS具有calc()用于执行简单计算的特殊功能这是一个用法示例:

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

在这里,calc()您可以尝试使用它的CSS代码 这篇文章的作者(我们今天将要翻译的译本)想谈谈所有有关此非常有用的功能的知识。





Calc()函数和CSS属性值


可以使用该功能的唯一地方calc()是CSS属性值。看下面的示例,其中使用此函数设置各种属性的值。

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

该函数calc()还可用于设置属性的任何单独部分:

.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()函数是用于处理数字属性的工具。


请注意,在以上所有示例中,我们在使用calc()数值属性时都使用该函数。我们还将讨论使用数字属性的一些功能(它们与有时不需要使用度量单位的事实有关)。现在,我们注意到该函数旨在使用数字执行操作,而不是使用字符串或其他操作。

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

存在能够在CSS被用来指定的元素和它们的部件的尺寸测量的许多单位:px%emreminmmcmptpcexchvhvwvminvmax所有这些单元均可与功能一起使用calc()

此功能也可以使用不指定单位的数字:

line-height: calc(1.2 * 1.2);

它也可以用来计算角度:

transform: rotate(calc(10deg * 5));

在传递给它的表达式中不执行任何计算的情况下,也可以使用此函数:

.el {
  /*   ,    */
  width: calc(20px);
}

Calc()不能在媒体查询中使用


尽管此函数旨在设置CSS属性值,但不幸的是,它不适用于媒体查询:

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

/*  ! */
@media (min-width: calc(40rem + 1px)) {
  /* ,  40rem */
}

如果这种构造一旦证明是可行的,那将是非常好的,因为这将允许创建看起来非常合乎逻辑的互斥媒体查询(例如,上面显示的查询)。

在一个表达式中使用不同的单位


一个表达式中使用不同度量单位的可允许性可能是最有价值的机会calc()几乎所有上述示例都使用了类似的方法。在这里,只是为了引起您的注意,另一个示例说明了不同度量单位的用法:

/*      */
width: calc(100% - 20px);

该表达式如下:“宽度等于从中减去20个像素的元素的宽度。”

在元件的宽度可以改变的情况下,完全不可能仅使用以像素表示的指示符来预先计算期望值。换句话说,您无法calc()使用Sass之类的东西进行预处理并尝试获取polyfill之类的东西。是的,鉴于浏览器支持的calc()很好,所以这不是必需的。这里的要点是这样的计算,其中以不同单位表示的值是混合的,必须在浏览器中执行(在页面的``执行''期间)。即,执行这种计算的能力是主要价值calc()

这是使用以不同单位表示的值的更多示例:

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

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

您可能可以预处理这些表达式,因为它们混合了值,这些值的单位与在浏览器中运行页面时确定的任何内容都不相关。

calc()与预处理器计算的比较


我们刚刚说过,最有用的功能calc()不适用于预处理。但是预处理为开发人员提供了一些与功能匹配的功能calc()例如,当使用Sass时,您还可以计算属性值:

$padding: 1rem;

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

在这里,可以进行计算以指示度量单位,在这里您可以添加以相同度量单位表示的数量,可以将某些值乘以未显示单位的值。但是无法使用以不同度量单位表示的值执行计算。这样的计算会施加类似于限制的限制calc()(例如,乘或除的数必须是无单位的值)。

公开CSS中使用的数值的含义


即使您没有利用仅在帮助下才能获得的机会calc(),此功能也可以用于揭示 CSS中使用的值含义。假设您希望属性的值恰好是元素宽度的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()函数的数学运算符


该表达的帮助下进行评估calc(),你可以使用运营商+-*/但是在他们的应用程序中有一些功能。

加(+)和减(-)时,必须将值与指定单位一起使用

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

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

请注意,使用不正确的值会导致特定声明也变得不正确的事实。

除以(/)时,必须不要在第二个数字上显示测量单位

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

  /*  */
  margin: calc(30px / 10px);

  /*  (   ) */
  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)),但这是一种情况的示例,在这种情况下,空格不仅是必需的,而且在表达清晰方面也很有用。

Tab Atkins告诉我,实际上,加法和减法运算符应该用空格分隔的原因是解析表达式的特殊性。我不能说我完全理解这一点,但是,例如,解析器将表达式处理2px-3px2带有度量单位的数字px-3px。没有人会需要如此奇怪的度量单位。用加法运算符解析表达式有其自身的问题。例如,解析器可以将此运算符作为用于描述数字的语法的一部分。我认为需要一个空格来正确处理自定义属性(--的语法,但事实并非如此。

当乘除运算符时,不需要空格。但是我相信您可以建议对这些运算符使用空格,以提高代码的可读性,并避免忘记空格以及在输入使用加法和减法的表达式时。

将括号calc()与表达式分开的空格不起作用。如果需要,甚至可以通过移动到新行来选择表达式:

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

是的,您在这里应该小心。函数名称(calc)与第一个左括号之间不应有空格:

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

嵌套构造:calc(calc())


使用函数时calc(),可以使用嵌套结构,但这并不是必须的。这类似于不使用括号时使用calc

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

从函数构建嵌套结构是没有意义的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(),即有关使用具有不同单位的值的计算的信息。此功能的另一个有趣功能是如何将其与自定义CSS属性一起应用。可以为自定义属性分配可以在计算中使用的值:

html {
  --spacing: 10px;
}

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

我敢肯定,可以想象通过设置自定义CSS属性的值来在一个地方完成许多设置的一组CSS样式。这些值将在整个CSS代码中使用。

此外,自定义属性可以相互引用(请注意,calc()此处未使用)。所获得的值可用于设置其他CSS属性的值(但是在这里您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代码。有时这可能非常有用。例如,在Splitting.js中,索引被添加到单词和符号中。

<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 {
  /*    ,  ,        */
  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()仅适用于使用字符串并使用它设置CSS属性content也就是说,这种设计非常有效:

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

我在这里说这个是因为有人可能想尝试从HTML代码中提取attr()某个数字并将其用于计算中:

<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()CSS源代码中所述相同的表达式


Firefox开发人员工具的“规则”选项卡

如果需要找出函数将要计算的内容calc(),则可以引用该选项卡Computed(可以在我所知道的所有浏览器的开发人员工具中找到该选项卡)。在那里将显示计算出的值calc()


Chrome开发者工具“计算”标签

浏览器支持


在这里,您可以找到有关该功能的calc()浏览器支持的信息如果我们谈论现代浏览器,则支持水平calc()超过97%。如果您需要支持相当旧的浏览器(例如IE 8或Firefox 3.6),则通常会这样做:在calc()该属性之前添加相同的属性,以计算其值以旧浏览器可以理解的格式设置:

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

该功能calc()有许多已知的问题,但是只有旧的浏览器会遇到这些问题。Caniuse上可以找到13种此类问题的描述。这里是其中的一些:

  • 版本59以下的Firefox浏览器不支持calc()用于设置颜色的功能。例如:color: hsl(calc(60 * 2), 100%, 50%)
  • 如果IE 9-11 box-shadow用于确定任何值,则IE 9-11将不会渲染该属性指定的阴影calc()
  • width: calc()当应用于表单元格时,IE 9-11和Edge都不支持视图设计

生活例子


我询问了几位CSS开发人员上次使用该功能的时间calc()他们的答案只是一个很小的选择,它将帮助所有人了解其他程序员calc()在日常工作中的用法

  • 我曾经calc()为管理领域创建助手类.full-bleed { width: 100vw; margin-left: calc(50% — 50vw); }我可以说这calc()是我最常用的3个CSS功能。
  • 我使用此函数为页面的固定“页脚”分配空间。
  • calc() . , font-size, . font-sizecalc() line-height. ( , calc() , , , rem em. , ).
  • , . . — : .margin { width: calc( (100vw — var(--content-width)) / 2); }.
  • calc() - , . : .drop-cap { --drop-cap-lines: 3; font-size: calc(1em * var(--drop-cap-lines) * var(--body-line-height)); }.
  • , .
  • , padding vw/vh.
  • 我申请calc()规避限制background-position对于限制渐变中颜色变化位置的调整尤其如此。例如,这可以描述如下:“放置颜色变化的位置,不到达0.75em底部”。



亲爱的读者们!您使用CSS calc()吗?

All Articles