天天看點

為什麼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 編寫代碼,請考慮使用數值作為後備。

最後