瞭解CSS/CSS3原生變數var

張鑫旭發表於2017-04-04

  一、變數是個好東西

  在任何語言中,變數的有一點作用都是一樣的,那就是可以降低維護成本,附帶還有更高效能,檔案更高壓縮率的好處。

  隨著CSS預編譯工具Sass/Less/Stylus的關注和逐漸流行,CSS工作組迅速跟進CSS變數的規範制定,並且,很多瀏覽器已經跟進,目前,在部分專案中已經可以直接使用了。

CSS變數var相容性截圖

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

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

  CSS中原生的變數定義語法是:--*,變數使用語法是:var(--*),其中*表示我們的變數名稱。關於命名這個東西,各種語言都有些顯示,例如CSS選擇器不能是數字開頭,JS中的變數是不能直接數值的,但是,在CSS變數中,這些限制通通沒有,例如:

: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定義的變數,只有id為alert的元素才能享有。如果你想變數全域性使用,則你可以設定在: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變數的空格尾隨特性

  請看下面這個例子:

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欄,如下圖:

預設進去demo UI 截圖

  隨著瀏覽器寬度減小,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欄下的效果就是這樣,字號,間距隨著欄目數量的減小也一併減小了,然後每欄之間間距是擴大了:

2欄下的效果截圖

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

  三、結束語

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

  多人合作專案我也會使用Less/Sass之類的預編譯工具,但是,基本上用到的就是變數,其他高階功能,幾乎都不怎麼使用。所以,如果瀏覽器全方位支援了原生的CSS變數,我十有八九就會拋棄Less/Sass之類的工具。

相關文章