本文首發於個人博客javascript
一直以來,CSS做爲一種申明式的樣式標記語言,很難像如javascript
等命令式編程語言同樣經過定義和使用變量的方式來維護和追蹤某些狀態。後來隨着scss
,less
等CSS預處理器的出現,咱們能夠像優秀的開源框架bootstrap
那樣,經過維護一個_variables.scss
變量文件的方式來維護一個龐大的項目。但預處理須要編譯,並不是CSS原生支持。而如今,咱們能夠在原生CSS中使用變量了!css
先來兩個在線demo感覺一下:html
CSS變量,也稱爲CSS自定義屬性。經過以--
開頭的自定義屬性來設置變量名,存儲一些特定值,在須要的地方使用var()
來訪問。如:
p { --primary-color: #6bc30d; color: var(--primary-color); }
能夠像定義任何css屬性同樣來申明變量,不一樣的是,變量名必須以--
開頭。如 --primary-color: #6bc30d
java
而要使用一個變量的值,須要使用 var() 函數,並將變量的名稱做爲參數傳入。 如 color: var(--primary-color);
git
var()
函數var()函數能夠代替元素中任何屬性中的值的任何部分。
var()
函數接受兩個參數,參數一是要替換的自定義屬性的名稱,參數二是可選的,做爲參數一無效時候的回退值(若是第一個參數引用的自定義屬性無效,則該函數將使用第二個值)。github
var( <custom-property-name> [, <declaration-value> ]? ) /*<custom-property-name> 自定義屬性名*/ /*<declaration-value> 聲明值(回退值)*/
--
開頭/*這樣是錯誤的*/ 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*/ }
/*這是兩個不一樣的變量*/ :root { --color: blue; --COLOR: red; }
scss
等CSS預處理中變量的區別雖然能夠在css的任何地方定義變量,可是css變量也是有做用域的。CSS的變量做用域分爲全局做用域和局部做用域。所以在申明一個變量以前,首先要肯定這個變量要用在哪裏?編程
經過在:root
中申明變量,就能夠申明一個全局變量,能夠在整個文檔結構中使用這個變量,由於CSS變量是可繼承的。bootstrap
: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 */ }
就像其餘CSS屬性同樣,在html中能夠經過內聯變量
來設置變量的值,而且也可以正常工做
<style> p { color: var(--color); } </style> <body> <p style="--color:red; --font-size: 50px; font-size:var(--font-size);"> 我使用內聯變量值得方式來設置樣式 <!-- 將顯示爲字號50px,顏色紅色 --> </p> </body>
能夠根據屏幕寬度的變化來改變變量的值,從而更容易的實現響應式佈局。
: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; } }
css變量是DOM的一部分,這意味着咱們能夠經過javascript
來訪問/修改css變量的值,這是scss
等css預處理器所作不到的。
要用JavaScript來更新CSS變量,須要調用已聲明變量元素上的style
對象上的 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>
本文首發於個人博客