CSS變數var()語法和用法和特性

少有人走的路發表於2019-03-20

CSSåévar兼容æ§æªå¾

Chrome/Firefox/Safari瀏覽器都是綠油油的,相容性大大超出我的預期,於是果斷嚐鮮記錄下語法用法和特性。

:root {
  --1: #369;
}
body {
  background-color: var(--1);
}複製程式碼

結果背景色如下:
變數背景色示意

但是,不能包含$[^(%等字元,普通字元侷限在只要是“數字[0-9]”“字母[a-zA-Z]”“下劃線_”和“短橫線-”這些組合,但是可以是中文,日文或者韓文,例如:

body {
  --深藍: #369;
  background-color: var(--深藍);
}複製程式碼

所以,我們就可以直接使用中文名稱作為變數,即使英語4級沒過的小夥伴也不會有壓力了,我們也不需要隨時掛個翻譯器在身邊了。

無論是變數的定義和使用只能在宣告塊{}裡面,例如,下面這樣是無效的:

--深藍: #369;
body {
  background-color: var(--深藍);
}複製程式碼

變數的定義,或者說宣告跟CSS計數器的宣告類似的,你應該擺脫Sass/Less等預編譯工具語法先入為主的語法影響,把CSS的原生變數理解為一種CSS屬性。

這樣,你就對其權重和變數應用規則要容易理解地多。

例如下面這個例子:

:root { --color: purple; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }

<p>我的紫色繼承於根元素</p>
<div>我的綠色來自直接設定</div>
<div id='alert'>
  ID選擇器權重更高,因此阿拉是紅色!
  <p>我也是紅色,佔了繼承的光</p>
</div>
複製程式碼

上面這個例子我們可以獲得這些資訊:

  1. 變數也是跟著CSS選擇器走的,如果變數所在的選擇器和使用變數的元素沒有交集,是沒有效果的。例如#alert定義的變數,只有idalert的元素才能享有。如果你想變數全域性使用,則你可以設定在:root選擇器上;
  2. 當存在多個同樣名稱的變數時候,變數的覆蓋規則由CSS選擇器的權重決定的,但並無!important這種用法,因為沒有必要,!important設計初衷是幹掉JS的style設定,但對於變數的定義則沒有這樣的需求。

CSS屬性名可以走變數嗎?

類似下面這樣:

body {
    --bc: background-color;    
    var(--bc): #369;
}複製程式碼

答案是“不可以”,要是可以支援的話,那CSS的壓縮可就要逆天了,估計所有的屬性都會變成1~2個字元。

CSS變數支援同時多個宣告嗎?

類似下面這樣:

不好意思,類似不了,語法上就根本不支援。

CSS變數使用完整語法
CSS變數使用的完整語法為:var( [, ]? ),用中文表示就是:var( <自定義屬性名> [, <預設值 ]? )

意思就是,如果我們使用的變數沒有定義(注意,僅限於沒有定義),則使用後面的值作為元素的屬性值。舉個例子:

.box {
  --1: #369;
}
body {
  background-color: var(--1, #cd0000);
}複製程式碼

則此時的背景色是#cd0000
紅色背景色

CSS變數不合法的預設特性

請看下面這個例子:

body {
  --color: 20px;
  background-color: #369;
  background-color: var(--color, #cd0000);
}複製程式碼

請問,此時<body>的背景色是?

A. transparent    B. 20px     C. #369      D. #cd0000複製程式碼

答案是…………………………A. transparent

不知大家答對了沒有!

這是CSS變數非常有意思的一個點,對於CSS變數,只要語法是正確的,就算變數裡面的值是個亂七八糟的東西,也是會作為正常的宣告解析,如果發現變數值是不合法的,例如上面背景色顯然不能是20px,則使用背景色的預設值,也就是預設值代替,於是,上面CSS等同於:
body {
--color: 20px;
background-color: #369;
background-color: transparent;
}

千萬不能想當然得認為等同於background-color:20px,這也是為什麼上面要強調CSS預設值的使用僅限於變數未定義的情況,並不包括變數不合法。

CSS變數的空格尾隨特性 更多問題CSS/CSS3繼續閱讀

請看下面這個例子:

body {
  --size: 20;   
  font-size: var(--size)px;
}複製程式碼

請問,此時<body>font-size大小是多少?

如果你以為是20px就太天真了,實際上,此處font-size:var(--size)px等同於font-size:20 px,注意,20後面有個空格,所以,這裡的font-size使用的是<body>元素預設的大小。因此,就不要妄圖取消就使用一個數值來貫穿全場,還是使用穩妥的做法:

body {
  --size: 20px;   
  font-size: var(--size);
}複製程式碼

或者使用CSS3 calc()計算:

body {
  --size: 20;   
  font-size: calc(var(--size) * 1px);
}複製程式碼

此時,<body>font-size大小才是20px

CSS變數的相互傳遞特性

就是說,我們在CSS變數定義的時候可以直接引入其他變數給自己使用,例如:

body {
  --green: #4CAF50;   
  --backgroundColor: var(--green);
}複製程式碼

或者更復雜的使用CSS3 calc()計算,例如:

body {
  --columns: 4;
  --margins: calc(24px / var(--columns));
}複製程式碼

對於複雜佈局,CSS變數的這種相互傳遞和直接引用特性可以簡化我們的程式碼和實現成本,尤其和動態佈局在一起的時候,無論是CSS的響應式後者是JS驅動的佈局變化。

我們來看一個CSS變數與響應式佈局的例子,您可以狠狠地點選這裡:CSS變數與響應式佈局例項demo

預設進去是4欄,如下圖:

隨著瀏覽器寬度減小,4欄可能就變成3欄,2欄甚至1欄,我們實際開發的時候,顯然不僅僅是欄目數量變化,寬度小,往往意味著訪問裝置尺寸有限,此時我們往往會縮小空白間距以及文字字號大小,這樣,有限螢幕才能顯示更多內容。

也就是說,當我們響應式變化的時候,改變的CSS屬性值不是1個,而是3個或者更多,如果我們有3個響應點,是不是就至少需要9個CSS宣告?但是,由於我們有了CSS變數,同時,CSS變數可以傳遞,當我們遭遇響應點的時候,我們只需要改變一個CSS屬性值就可以了。

下面就是本demo核心CSS程式碼(只需要改變--columns這一個變數即可):

.box {
    --columns: 4;
    --margins: calc(24px / var(--columns));
    --space: calc(4px * var(--columns));
    --fontSize: calc(20px - 4 / var(--columns));
}
@media screen and (max-width: 1200px) {
    .box {
        --columns: 3;
    }
}
@media screen and (max-width: 900px) {
    .box {
        --columns: 2;
    }
}
@media screen and (max-width: 600px) {
    .box {
        --columns: 1;
    }
}複製程式碼

於是,我們在2欄下的效果就是這樣,字號,間距隨著欄目數量的減小也一併減小了,然後每欄之間間距是擴大了:

有沒有覺得CSS越來越屌了呢!哈哈~

三、結束語

由於目前幾乎沒有關於CSS3 var()的文章,因此,上面關於var()的語法特性等都是自己通過看規範文件,外加細緻的測試得到的。但是,一個人的能力總是有限的,因此,必然還有很多var()變數有意思的點沒發現,因此,就希望大家若是發現var()其他有意思的地方,歡迎評論告知,我們及時新增在文章中,方便你我他她它。


相關文章