在原生CSS中使用變數

Smohan發表於2019-03-04

本文首發於我的部落格

一直以來,CSS作為一種申明式的樣式標記語言,很難像如javascript等指令式程式設計語言一樣通過定義和使用變數的方式來維護和追蹤某些狀態。後來隨著scss,less等CSS前處理器的出現,我們可以像優秀的開源框架bootstrap那樣,通過維護一個_variables.scss變數檔案的方式來維護一個龐大的專案。但預處理需要編譯,並非CSS原生支援。而現在,我們可以在原生CSS中使用變數了

先來兩個線上demo感受一下:

定義

CSS變數,也稱為CSS自定義屬性。通過以--開頭的自定義屬性來設定變數名,儲存一些特定值,在需要的地方使用 var() 來訪問。如:

p {
  --primary-color: #6bc30d;
  color: var(--primary-color);
}
複製程式碼

如何申明變數

可以像定義任何css屬性一樣來申明變數,不同的是,變數名必須以--開頭。如 --primary-color: #6bc30d

如何使用變數

而要使用一個變數的值,需要使用 var() 函式,並將變數的名稱作為引數傳入。 如 color: var(--primary-color);

var()函式

var()函式可以代替元素中任何屬性中的值的任何部分。

var() 函式接受兩個引數,引數一是要替換的自定義屬性的名稱,引數二是可選的,作為引數一無效時候的回退值(如果第一個引數引用的自定義屬性無效,則該函式將使用第二個值)。

var( <custom-property-name> [, <declaration-value> ]? )
/*<custom-property-name> 自定義屬性名*/
/*<declaration-value> 宣告值(回退值)*/
複製程式碼

使用變數的意義

  • 無需多次定義,同樣的屬性可以重複使用
  • 讓CSS檔案可讀易維護(如主題樣式,只需修改一個變數即可,而不再是枯燥的查詢替換),靈活性更高

注意點

  • 變數名稱必須以 -- 開頭
  • 變數只能儲存一個屬性的值,而不能用來儲存一個屬性,如下例子是錯誤的:
/*這樣是錯誤的*/
p {
  --primary-color: color;
  var(--primary-color) : #6bc30d
}
複製程式碼
  • 變數中無法使用加減等數學方法,如果需要使用計算,則可以使用 calc 函式:
/*這樣是錯誤的*/
p {
  --font-size : 20px * 2;
  font-size: var(--font-size);
}
/*這樣是正確的*/
p {
  --font-size : calc(20px * 2);
  font-size: var(--font-size); /*40px*/
}
/*這樣拼接也是無效的*/
p {
  --font-size: 20;
  font-size: var(--font-size)px; /*無效*/
}
/*這樣是有效的:*/
p {
  --font-size: 20;
  font-size: calc(var(--font-size) * 1px); /*20px*/
}
複製程式碼
  • CSS變數是區分大小寫的
/*這是兩個不同的變數*/
:root {
 --color: blue;
--COLOR: red;
}
複製程式碼

scss等CSS預處理中變數的區別

  • CSS變數是瀏覽器原生支援的,不需要經過編譯就可以使用
  • CSS變數是DOM的一部分,可以使用JS直接修改

作用域

雖然可以在css的任何地方定義變數,但是css變數也是有作用域的。CSS的變數作用域分為全域性作用域和區域性作用域。因此在申明一個變數之前,首先要確定這個變數要用在哪裡?

全域性變數

通過在:root中申明變數,就可以申明一個全域性變數,可以在整個文件結構中使用這個變數,因為CSS變數是可繼承的。

:root{
  --primay-color: #6bc30d;
}
/* 在任何地方都可以使用`:root`中定義的全域性變數 */
p, div , a {
  color : var(--primay-color);
}
#myDiv, .myDiv {
  color : var(--primay-color);
}
複製程式碼

區域性變數

可以在除:root外的任何地方申明區域性變數。但是區域性變數只能夠在被申明的元素及其子元素中使用。區域性變數更多的應用在值覆蓋上。

.modal {
  --modal-padding-top: 30px;
}
/*當前元素及其子元素中使用*/
.modal, 
.modal-content {
  padding-top: var(--modal-padding-top); /*30px*/;
}
/*在其他元素上無效*/
body {
  padding-top: var(--modal-padding-top); /*無效設定,使用預設值*/
}
複製程式碼

變數的繼承

與其他CSS屬性一樣,CSS中的變數也是可以繼承的。

:root{
  --color: red;
}
P {
  --pColor: green;
  color: var(--color); /*red*/
}
p > span{
  color : var(-pColor); /*green*/
}
複製程式碼
css變數繼承

多個申明中變數的優先順序

同名變數可以重複申明,這樣變數就會有了優先順序的問題,如下例子:

:root {
  --color: red;
}
div {
  --color: green;
}
#myDiv {
  --color: yellow; 
  --color: blue; 
}
* {
  color: var(--color);
}
複製程式碼
<p>我正常顯示紅色</p>
<div>我顯示綠色</div>
<div id="myDiv">
  我顯示藍色
  <p>那麼我呢?</p>
</div>
複製程式碼
變數優先順序

如圖,div中的區域性變數覆蓋了:root中設定的值,而特定ID的div元素#myDiv又覆蓋了div中的值,最後作為#myDiv的子元素p繼承了其父級的值,而不是使用root中申明的值

無效變數

對於變數來講,CSS屬性的有效性並不適用。對於變數這種自定義屬性,即便在上下文環境中這個值是無意義的,但是都能夠通過var()函式呼叫。無意義的變數值會導致無效的CSS申明。通過var()函式呼叫後會被解析為初始值。

:root {
  --color: 20px;
}
p {
  --font-size: green;
  background-color: var(--color); 
  /* background-color: 20px; 無效,將回退為transparent */
}
複製程式碼

在html屬性中使用css變數

就像其他CSS屬性一樣,在html中可以通過內聯變數來設定變數的值,並且也能夠正常工作

<style>
  p {
    color: var(--color);
  }
</style>
<body>
  <p style="--color:red; --font-size: 50px; font-size:var(--font-size);">
    我使用內聯變數值得方式來設定樣式
    <!-- 將顯示為字號50px,顏色紅色 -->
  </p>
</body>
複製程式碼

在媒體查詢中使用css變數

可以根據螢幕寬度的變化來改變變數的值,從而更容易的實現響應式佈局。

:root {
  --font-size: 30px;
  --color: red;
}
html{
  color: var(--color);
  font-size: var(--font-size);
}

@media screen and (min-width: 480px) {
  :root {
    --font-size: 50px;
    --color: green;
  }
}
@media screen and (min-width: 760px) {
  :root {
    --font-size: 100px;
    --color: blue;
  }
}
複製程式碼
媒體查詢改變變數值

在js中使用css變數

css變數是DOM的一部分,這意味著我們可以通過javascript來訪問/修改css變數的值,這是scss等css前處理器所做不到的。
要用JavaScript來更新CSS變數,需要呼叫已宣告變數元素上的style物件上的 setProperty 方法。

setProperty()

//語法
element.style.setProperty(propertyName, value, priority);
//propertyName 是一個 DOMString 被更改的CSS屬性.
//value <可選> 是一個 DOMString 新的屬性值. 如果沒有指定, 則當作空字元.不能包含 "!important"
//priority <可選> 是一個 DOMString。允許 "important" CSS 優先被設定. 如果沒有指定, 則當作空字元.

//在根元素(html)上更新變數值
document.documentElement.style.setProperty(propertyName, value)
複製程式碼

示例

:root {
  --font-size: 20px;
  --background: red;
}
body {
  font-size: var(--font-size);
  background-color: var(--background);
  color: #fff;
}
複製程式碼
<h1>使用JavaScript來改變背景色</h1>
 <button data-value="red">紅色</button>
 <button data-value="green">綠色</button>
 <button data-value="blue">藍色</button>
 <button data-value="yellow">黃色</button>

 <script>
   let $buttons = document.querySelectorAll(`button`)
   $buttons.forEach(button => {
     button.addEventListener(`click`, () => {
       let value = button.dataset.value
       document.documentElement.style.setProperty(`--background`, value)
     })
   })
 </script>
複製程式碼
使用JavaScript來改變背景色

參考文件

本文首發於我的部落格

相關文章