天天看点

为什么CSS中的calc函数可能会不生效?

前言

在早期如果想要对某一些样式进行动态计算,绝大多数的做法都是使用JavaScript来进行,当时的CSS在面对这种场景显得有点无能为力。但是,当CSS3中新增了​

​calc​

​​函数时,面对这种场景,JavaScript不再是我们的第一选择,我们只用 CSS 就可以进行相当复杂的计算了。在使用​

​calc​

​的过程中,相信大家或多或少都遇到过下面这些“坑”。

如果这篇文章有帮助到你,❤️关注+点赞❤️鼓励一下作者,文章公众号,关注 ​

​前端南玖​

​ 第一时间获取最新文章~

常见的“坑”

先来介绍css使用​

​calc​

​无效的两种常见情况:

运算符之间没加空格

/*错误写法*/
div{
      width: calc(100%-50px);
}
/*正确写法*/
div{
      width: calc(100% - 50px);
}      

这里错误写法中​

​-​

​​两边没加空格,导致width不生效。但并不是所有运算符间都需要加空格,只有 ​

​+​

​​ 和 ​

​-​

​ 需要加空格,因为运算允许负数的出现,如:

div{
      width: calc(100% + -50px);
}      

所以,为了统一,建议所有运算符都加上空格,防止记忆混淆。

运算值没带单位

我们都知道在写css时,如果数值为0我们一般会省略它的单位,比如:​

​0px​

​​我们一般会直接写成​

​0​

​​。但是在​

​calc()​

​函数中如果0不带单位,也会导致不生效。

/*错误写法*/
div{
      width: calc(0 + 100px);
}
/*正确写法*/
div{
      width: calc(0px + 100px);
}      

这里上面的不带单位的写法也是不生效的。这里我相信很多人都会有疑问,为什么0还需要带个单位?

这是因为​

​calc() ​

​函数传入的是一个数学表达式,而表达式的值可以有多种类型,如长度、百分比、角度等。那如果你传个 0 进去,没单位的话,怎么知道这个 0 是属于什么类型?

低版本less处理calc冲突

以下代码在低版本less中会被编译成你意想不到的结果:

.box {
  width: calc(100% - 50px)
}      

编译后:

.box {
  width: calc(50%)
}      

导致这个结果的原因在于less中有一套自己的运算规则:

less运算(Operations)

算术运算符 ​

​+​

​​、​

​-​

​​、​

​*​

​​、​

​/​

​ 可以对任何数字、颜色或变量进行运算。如果可能的话,算术运算符在加、减或比较之前会进行单位换算。计算的结果以最左侧操作数的单位类型为准。如果单位换算无效或失去意义,则忽略单位。无效的单位换算例如:px 到 cm 或 rad 到 % 的转换。

// 所有操作数被转换成相同的单位
@conversion-1: 5cm + 10mm; // 结果是 6cm
@conversion-2: 2 - 3cm - 5mm; // 结果是 -1.5cm

// conversion is impossible
@incompatible-units: 2 + 5px - 3cm; // 结果是 4px

// example with variables
@base: 5%;
@filler: @base * 2; // 结果是 10%
@other: @base + @filler; // 结果是 15%      

乘法和除法不作转换。因为这两种运算在大多数情况下都没有意义,一个长度乘以一个长度就得到一个区域,而 CSS 是不支持指定区域的。Less 将按数字的原样进行操作,并将为计算结果指定明确的单位类型。

所以上面的less会被进行如下处理:

  • 由于100%与50px单位不同,会被转换成相同的单位%(以最左侧操作数的单位类型为准)
  • 再进行减法运算得到50%

解决方案

  • 转义
转义(Escaping)允许你使用任意字符串作为属性或变量值。任何 ​

​~"anything"​

​​ 或 ​

​~'anything'​

​ 形式的内容都将按原样输出,除非 ​​interpolation​​。

我们希望less不要帮我们处理,所以这里我们可以使用less的转义语法让​

​calc​

​函数原样输出就好了

.box {
  width: calc(~"100% - 50px")
}      
  • 升级​

    ​less​

    ​​和​

    ​less-loader​

了解calc函数

CSS calc 函数用于在指定 CSS 属性值时执行计算。它可以用于可以使用任何数值的地方。它将表达式作为参数,并将结果用作使用它的 CSS 属性的值。我们可以用它进行加法​

​+​

​​、减法​

​-​

​​、乘法​

​*​

​​和除法​

​/​

​。

语法

/* property: calc(expression) */
width: calc(100% - 80px);      

calc() 函数用一个表达式作为它的参数,用这个表达式的结果作为值。这个表达式可以是任何如下操作符的组合,采用标准操作符处理法则的简单表达式。

  • ​+​

    ​ 加法
  • ​-​

    ​ 减法
  • ​*​

    ​ 乘法,乘数中至少有一个是 number
  • ​/​

    ​ 除法,除数必须是number

规则

  • ​+​

    ​ 和 ​

    ​-​

    ​ 运算符的两边必须要有空白字符。 比如,​

    ​calc(50% -8px)​

    ​​ 会被解析成为一个无效的表达式,解析结果是:一个百分比 后跟一个负数长度值。而加有空白字符的、有效的表达式 ​

    ​calc(8px + -50%)​

    ​ 会被解析成为:一个长度 后跟一个加号 再跟一个负百分比。
  • ​*​

    ​​ 和 ​

    ​/​

    ​ 这两个运算符前后不需要空白字符,但如果考虑到统一性,仍然推荐加上空白符。
  • 用 0 作除数会使 HTML 解析器抛出异常。
  • 涉及自动布局和固定布局的表格中的表列、表列组、表行、表行组和表单元格的宽度和高度百分比的数学表达式,​

    ​auto​

    ​ 可视为已指定。
  • ​calc()​

    ​​ 函数支持嵌套,但支持的方式是:把被嵌套的 ​

    ​calc()​

    ​ 函数全当成普通的括号。

解惑

想要了解前面那些坑产生的原因,我们得先了解CSS中的基础语法与数据类型:

DIMENSION语法

DIMENSION    {num}{ident}      
为什么CSS中的calc函数可能会不生效?

这里的​

​num​

​​值的是数字,那么​

​ident​

​代表什么呢,这个我们也可以在CSS规范中找到答案

ident

ident    [-]?{nmstart}{nmchar}*      

nmstart和nmchar

nmstart [_a-z]|{nonascii}|{escape}

nmchar [_a-z0-9-]|{nonascii}|{escape}      
为什么CSS中的calc函数可能会不生效?

解惑calc(100%-50px)

了解完CSS的基础语法与数据结构,我们现在可以来看看解析器是如何解析​

​calc(100%-50px)​

​的。

  • 首先DIMENSION语法,{num}{ident}会将其分割为​

    ​num:100​

    ​​、​

    ​ident:%和-100px​

  • ​%​

    ​是单位,这个应该没有疑问
  • ​-100px​

    ​​这个符合nmchar语法,所以没有将其拆开,而是保留作为单位解析,但CSS中没有​

    ​-100px​

    ​这个单位,所以这个表达式不会生效

兼容性

calc 函数具有惊人的浏览器支持,一直到 IE9。如果你用旧版浏览器或 Opera Mini 编写代码,请考虑使用数值作为后备。

最后