本文首發於我的博客
一直以來,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*/
}
多個申明中變量的優先級
同名變量可以重復申明,這樣變量就會有了優先級的問題,如下例子:
: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>
參考文檔
- Using CSS custom properties (variables)
- CSS Variables overview
- Everything you need to know about CSS Variables
本文首發於我的博客