英文:Maria Antonietta Perna? 譯文:葡萄城控件?
www.cnblogs.com/powertoolsteam/p/css-variables.html
Sass和Less這樣的預(yù)處理器目代,讓我們的CSS代碼保持良好的結(jié)構(gòu)和可維護(hù)性病往。像變量、混合(mixins)奉狈、循環(huán)控制等特性鳖昌,增強(qiáng)了動(dòng)態(tài)編寫CSS的能力备畦,從而減少重復(fù)代碼,也加快了我們開發(fā)速度许昨。
近年來(lái)懂盐,一些動(dòng)態(tài)特性開始作為規(guī)范的一部分,出現(xiàn)在CSS語(yǔ)言中糕档。CSS變量(CSS variables)莉恼,或者用它的官方稱謂,叫作自定義屬性(custom properties),已經(jīng)可用类垫,并且有非常棒的瀏覽器支持司光,而CSS mixins也正在取得進(jìn)展。
在本文悉患,你將學(xué)會(huì)如何使用CSS變量残家,并把它集成到你的CSS開發(fā)流程中,讓你的樣式表更好維護(hù)售躁,且減少重復(fù)坞淮。
讓我們現(xiàn)在就開始吧!
什么是CSS變量陪捷?
如果你曾使用過(guò)某種編程語(yǔ)言回窘,那么你已經(jīng)很熟悉變量這個(gè)概念了。變量用于存儲(chǔ)和更新你的程序所需要的值市袖,以便使它運(yùn)行啡直。
例如,考慮下面的JavaScript代碼
let number1 = 2;
let number2 = 3;
let total = number1 + number2;
console.log(total); // 5
number1 = 4;
total = number1 + number2;
console.log(total); // 7
nubmer1和 number2是兩個(gè)變量苍碟,分別存儲(chǔ)著數(shù)字2和3酒觅。
total同樣是變量,存儲(chǔ)著number1與number2之和微峰。在這里它的值就是5舷丹。你可以動(dòng)態(tài)地修改變量里的值,并在程序中使用它們蜓肆。在上面的代碼中颜凯,我把number1的值更新為4,然后再進(jìn)行求和仗扬。使用相同的變量症概,這個(gè)時(shí)候total里存儲(chǔ)的值就是5,而不再是7了厉颤。
使用變量的妙處在于穴豫,它可以讓你在一個(gè)地方存儲(chǔ)值凡简,并且讓你在后面能以各種理由去更新它逼友。在程序中,你不需要為不同的值再添加額外的字符表示:任何值的更新都發(fā)生在同一個(gè)地方秤涩。正如帜乞,在你定義的變量上。
CSS在很大程度上是一種聲明式的語(yǔ)言筐眷,而缺少動(dòng)態(tài)能力黎烈。你也許會(huì)認(rèn)為,讓CSS擁有變量,幾乎讓上面的說(shuō)法自相矛盾照棋。如果前端開發(fā)僅僅是關(guān)于文字游戲资溃,那可以這么說(shuō)。幸運(yùn)的是烈炭,Web的編程語(yǔ)言很像生活中的語(yǔ)言溶锭,它們會(huì)隨著周圍環(huán)境和實(shí)踐需要而不斷進(jìn)化與適應(yīng)。CSS也同樣如此符隙。
簡(jiǎn)單的說(shuō)趴捅,變量已經(jīng)成為CSS世界中激動(dòng)人心的事實(shí),并且你即將親自看到霹疫,對(duì)于這個(gè)厲害的新技術(shù)拱绑,學(xué)習(xí)和使用起來(lái)都非常直觀。
使用CSS變量有什么好處丽蝎?
使用CSS變量的好處猎拨,跟在其他編程語(yǔ)言中使用變量的好處沒(méi)什么大的區(qū)別。
規(guī)范是這樣描述這一點(diǎn)的
使用CSS變量屠阻,給看似隨機(jī)的值加上富有信息的名字迟几,從而使得大文件更容易閱讀和編輯,更少出錯(cuò)栏笆。因?yàn)槔嗳阒恍枰谧远x屬性中改變一次值,所有應(yīng)用了這個(gè)變量的地方都會(huì)自動(dòng)跟著一起改變蛉加。W3C 規(guī)范
換句話說(shuō)蚜枢,通過(guò)給變量起一個(gè)對(duì)你來(lái)說(shuō)在項(xiàng)目中有意義的名字,你能更容易的管理和維護(hù)你的代碼针饥。例如厂抽,當(dāng)你為項(xiàng)目中的主色調(diào)設(shè)置一個(gè)變量名--primary-color,那么你后面再修改這個(gè)主色調(diào)時(shí)丁眼,只需要改動(dòng)一處筷凤,而不需要在不同位置的多個(gè)CSS文件中去手動(dòng)修改多次值。
CSS變量和預(yù)處理器中的變量有什么不同苞七?
你可能已經(jīng)在CSS預(yù)處理器中嘗試過(guò)使用變量而帶來(lái)的好處了藐守,比如Sass和Less。
預(yù)處理器讓你能設(shè)置變量蹂风,以及在函數(shù)卢厂、循環(huán)、數(shù)學(xué)計(jì)算等等地方中使用它們惠啄。這是否意味著CSS變量已經(jīng)無(wú)關(guān)緊要了呢慎恒?
那可未必任内,主要是因?yàn)椋珻SS變量與預(yù)處理器中的變量其實(shí)是不同的東西融柬。
這些不同基于一個(gè)事實(shí):CSS變量是瀏覽器中直接可用的CSS屬性死嗦,而預(yù)處理中的變量是用于編譯成常規(guī)的CSS代碼,瀏覽器其實(shí)對(duì)它們一無(wú)所知粒氧。
這意味著越走,你可以在樣式表中,在內(nèi)聯(lián)樣式中靠欢,在SVG的標(biāo)簽中直接更新CSS變量廊敌,甚至可以在運(yùn)行時(shí)用JavaScript直接修改它。而你是無(wú)法對(duì)預(yù)處理器中的變量做上面這些操作的门怪。CSS變量開啟了一個(gè)充滿可能性的新世界大門骡澈。
不是說(shuō)你必須要在兩者間做出選擇:沒(méi)有什么東西限制你,你可以同時(shí)使用CSS變量和預(yù)處理變量掷空,并享有它們各自帶來(lái)的巨大好處肋殴。
CSS變量:語(yǔ)法
雖然本文為了簡(jiǎn)潔,我使用了CSS變量(CSS variables)這個(gè)稱呼坦弟,但官方的規(guī)范把它們稱作作為級(jí)聯(lián)變量的CSS自定義屬性(CSS custom properties for cascading variables)护锤。*CSS自定義屬性(CSS custom property)*的部分看起來(lái)像這樣:
--my-cool-background: #73a4f4;
在自定義屬性前添加雙橫線前綴,然后像給普通CSS設(shè)值一樣酿傍,給自定義屬性設(shè)值烙懦。在上面的代碼中,我給一個(gè)叫做--my-cool-backgroud的自定義屬性設(shè)置了一個(gè)顏色值赤炒。
而 級(jí)聯(lián)變量(cascading variable) 的部分氯析,由通過(guò)val()來(lái)使用你的自定義屬性組成,開起來(lái)像這樣:
var(--my-cool-background);
自定義屬性作用于CSS選擇器中莺褒,val()可被當(dāng)成一個(gè)真正的CSS屬性一樣使用掩缓。
:root {
????--my-cool-background: #73a4f4;
}
/* CSS文件的其他部分 */
#foo {
????background-color: var(--my-cool-background);
}
上面的代碼片段把--my-cool-background這個(gè)自定義屬性的作用域定義在:root這個(gè)偽類中,這讓該自定義屬性能被全局訪問(wèn)到(即在<html>標(biāo)簽內(nèi)部的任何地方)遵岩。然后你辣,使用val()函數(shù)把ID為foo的容器的background-color設(shè)置為自定義屬性的值,這時(shí)該容器就有了淺藍(lán)的背景色尘执。
這還沒(méi)完舍哄。你可以用同樣的淺藍(lán)色,給多個(gè)HTML標(biāo)簽的多種可以設(shè)置顏色值的地方設(shè)值正卧,比如設(shè)置它們的color和border-color蠢熄。方法很簡(jiǎn)單跪解,就是通過(guò)var(--my-cool-background)拿到自定義屬性的值炉旷,然后給合適的CSS屬性設(shè)置上去签孔。(當(dāng)然,在事情變得復(fù)雜之前窘行,我建議思考一下你的CSS變量命名規(guī)范):
p {
????color: var(--my-cool-background);
}
示例1代碼饥追,可點(diǎn)擊查看(https://gitee.com/GrapeTech/css-variable-demo/blob/master/demo-1.html)
你還可以從通過(guò)利用CSS變量獲得另一個(gè)CSS變量的值。例如:
--top-color: orange;
--bottom-color: yellow;
--my-gradient: linear-gradient(var(--top-color), var(--bottom-color));
上面的代碼創(chuàng)建了一個(gè)--my-gradient變量罐盔,是一個(gè)漸變樣式但绕,它的值被設(shè)為--top-color的值和--bottom-color的值組合的結(jié)果。現(xiàn)在惶看,你可以在任何時(shí)候修改你的漸變樣式捏顺,僅僅是修改變量的值就可以了,而不再需要在樣式表里滿文件地去找用到這個(gè)漸變樣式地方纬黎。
示例2代碼(https://gitee.com/GrapeTech/css-variable-demo/blob/master/demo-2.html)
最后幅骄,你可以在CSS變量中加入一個(gè)或多個(gè)備用值(fallback value/s),例如:
var(--main-color, #333);
上面的代碼中本今,#333是一個(gè)備用值拆座。當(dāng)自定義屬性值無(wú)效或未指定(unset)時(shí),如果這時(shí)也沒(méi)有指定備用值冠息,那么被繼承的(inherited)屬性值將會(huì)被使用挪凑。
CSS變量是區(qū)分大小寫的
與普通CSS屬性不同,CSS變量是區(qū)分大小寫的逛艰。
例如躏碳,var(--foo)和var(--FOO)是在求兩個(gè)不同的自定義屬性值,分別是--foo和--FOO的散怖。
CSS變量受級(jí)聯(lián)關(guān)系影響
和普通CSS屬性一樣唐断,CSS變量是可繼承的。例如杭抠,我們定義了一個(gè)屬性脸甘,值為blue:
:root {
????--main-color: blue;
}
當(dāng)你給任意在<html>標(biāo)簽里的元素指定--main-color變量時(shí),它們都會(huì)繼承到blue這個(gè)值偏灿。
當(dāng)你在另一個(gè)元素里丹诀,為改自定義屬性設(shè)置了一個(gè)新值時(shí),那么所有該元素的子元素都會(huì)繼承那個(gè)新值翁垂。例如:
:root {
????--main-color: blue;
}
.alert {
????--main-color: red;
}
p {
????color: var(--main-color);
}
<--! HTML -->
<html>
??<head>
????<!-- head code here -->
??</head>
??<body>
????<div>
??????<p>blue 的段落</p>
??????<div class="alert">
????????<p>red 的段落</p>
??????</div>
????</div>
??</body>
</html>
在上面的標(biāo)簽中铆遭,第一個(gè)p段落會(huì)繼承到全局的--main-color值,它是藍(lán)色沿猜。
在div標(biāo)簽中擁有.alert類的段落會(huì)是紅色枚荣,因?yàn)樗闹道^承自局部作用域里的--main-color。
示例3代碼(https://gitee.com/GrapeTech/css-variable-demo/blob/master/demo-3.html)
知道目前這些規(guī)則差不多夠了啼肩。讓我們開始寫代碼吧橄妆!
如何在SVG中使用CSS變量
CSS變量和SVG配合得很好衙伶。你可以使用CSS變量去修改SVG中的樣式,以及和呈現(xiàn)相關(guān)的屬性害碾。
舉個(gè)例子矢劲,假設(shè)你想讓你的SVG圖標(biāo)能跟隨其所在父容器而擁有不同的顏色。你可以把CSS變量的作用域限定在父容器中慌随,然后給變量設(shè)置想要的顏色芬沉,那么里面的圖標(biāo)就會(huì)繼承父容器的顏色值。下面是相關(guān)代碼:
/* inline SVG symbol for the icon */
<svg>
??<symbol id="close-icon" viewbox="0 0 200 200">
????<circle cx="96" cy="96" r="88" fill="none" stroke="var(--icon-color)" stroke-width="15" />
????<text x="100" y="160" fill="var(--icon-color)" text-anchor="middle" style="font-size:250px;">x</text>
??</symbol>
</svg>
/* first instance of the icon */
<svg>
??<use xlink:href="#close-icon" />
</svg>
上面的代碼使用了<symbol>標(biāo)簽阁猜,它讓你創(chuàng)建一SVG圖形的不可見(jiàn)的版本丸逸。然后再使用<use>標(biāo)簽生成一個(gè)可見(jiàn)的副本。這種方法可以讓你根據(jù)自己的喜好創(chuàng)建任意多個(gè)自定義的圖標(biāo)剃袍,也就是通過(guò)它的ID(#close-icon)指向那個(gè)<symbol>椭员。這比一遍又一遍地寫重復(fù)的代碼創(chuàng)建圖形更加簡(jiǎn)便。如果你想提高這方便的技術(shù)笛园,Massimo Cassandro在他的Build Your Own SVG Icons中提供了一個(gè)快速教程隘击。
注意到SVG symbol中,circle元素里的stroke屬性和text元素里的fill屬性:它們都使用了CSS變量研铆,這里是--icon-color埋同。它被定義在:rootCSS文件的選擇器中,像這樣:
:root {
????--icon-color: black;
}
這是當(dāng)前圖標(biāo)看起來(lái)的樣子:
這時(shí)棵红,如果你把同樣的SVG圖標(biāo)放在不同的父容器中凶赁,并且在父容器上,給你的CSS變量設(shè)置各自的局部值逆甜,那么你就會(huì)得到不同顏色的圖標(biāo)虱肄,并且不用給你的樣式表添加多余的規(guī)則。這很酷交煞!
為了展示這一點(diǎn)咏窿,我們把同樣的圖標(biāo)放在一個(gè)有.success類的div里:
<!-- html -->
<div class="success">
????<svg>
????????<use xlink:href="#close-icon" />
????</svg>
</div>
現(xiàn)在,讓--icon-color變量局部化素征,即把它放在.success中集嵌,并設(shè)置一個(gè)green值。我們來(lái)看看發(fā)生的變化:
/* css */
.success {
????--icon-color: green;
}
這個(gè)圖標(biāo)的顏色就變成了綠色:
來(lái)看看一個(gè)完整的示例吧: 示例4代碼(https://gitee.com/GrapeTech/css-variable-demo/blob/master/demo-4.html)
如何在@keyframes中使用CSS變量
CSS變量可以在CSS動(dòng)畫中使用御毅,即可用于常規(guī)HTML元素根欧,也可以用于內(nèi)聯(lián)的SVG。只需要記得端蛆,你得知道讓什么元素動(dòng)凤粗,把它視為目標(biāo)元素,然后創(chuàng)建對(duì)該目標(biāo)元素的選擇器今豆,在選擇器的作用范圍中定義你的CSS變量嫌拣,然后柔袁,使用val()獲取這些變量,把它們?cè)O(shè)置到@keyframes代碼塊中亭罪。
例如瘦馍,讓SVG中.bubble類里面的<ellipse>元素動(dòng)起來(lái)歼秽,你的CSS可能會(huì)看起來(lái)像這樣:
.bubble {
??--direction-y: 30px;
??--transparency: 0;
??animation: bubbling 3s forwards infinite;
}
@keyframes bubbling {
??0% {
????transform: translatey(var(--direction-y));
????opacity: var(--transparency);
??}
??40% {
????opacity: calc(var(--transparency) + 0.2);
??}
??70% {
????opacity: calc(var(--transparency) + 0.1);
??}
??100% {
????opacity: var(--transparency);
??}
}
注意到這是如何借助CSS的calc()应役,并用var()函數(shù)進(jìn)行計(jì)算的。它們?cè)鰪?qiáng)了你代碼的靈活性燥筷。
這個(gè)例子簡(jiǎn)潔的地方在于箩祥,利用CSS屬性,你可以簡(jiǎn)單的修改相應(yīng)選擇器里變量值而調(diào)整動(dòng)畫肆氓,而不需要挨個(gè)去查找@keyframes里的屬性了袍祖。
這里有個(gè)完整的例子供你體驗(yàn):示例5代碼(https://gitee.com/GrapeTech/css-variable-demo/blob/master/demo-5.html)
如何通過(guò)JavaScript操作CSS變量
另一個(gè)超級(jí)酷的事情就是,你可以直接通過(guò)JavaScript代碼訪問(wèn)CSS變量谢揪。
假設(shè)在你的CSS文件中蕉陋,有一個(gè)叫做--left-pos的變量,作用在.sidebar選擇器中拨扶,值為100px:
.sidebar {
????--left-pos: 100px;
}
那么凳鬓,通過(guò)JavaScript獲取--left-pos值,會(huì)像下面這樣:
// 緩存你即將操縱的元素
const sidebarElement = document.querySelector('.sidebar');
// 緩存sidebarElement的樣式于cssStyles中
const cssStyles = getComputedStyle(sidebarElement);
// 獲取 --left-pos CSS變量的值
const cssVal = String(cssStyles.getPropertyValue('--left-pos')).trim();
// 將CSS 變量的值打印到控制臺(tái): 100px
console.log(cssVal);
如果想通過(guò)JavaScript設(shè)置CSS變量的值患民,你可以像這樣:
sidebarElement.style.setProperty('--left-pos', '200px');
上面的代碼將sidebar元素中--left-pos變量的值設(shè)置為200px缩举。
請(qǐng)看看CodePen中的如下示例,你可以交互式地點(diǎn)擊側(cè)邊欄匹颤,修改blend mode屬性和背景色仅孩。這些實(shí)現(xiàn)只用到了CSS變量和JavaScript。
示例6代碼(https://gitee.com/GrapeTech/css-variable-demo/blob/master/demo-6.html)
CSS變量的瀏覽器支持
除了IE11(它不支持CSS變量)印蓖,所有主流瀏覽器都對(duì)CSS變量有全面地支持辽慕。
對(duì)于不支持CSS變量的瀏覽器,一個(gè)變通的方案是使用具有虛擬查詢條件(dummy conditional query)的@supports代碼塊:
section {
????color: gray;
}
@supports(--css: variables) {
????section {
????????--my-color: blue;
????????color: var(--my-color, 'blue');
????}
}
考慮到@supports在IE/Edge里也起作用赦肃,上面的方法是可行的誓军。如果你在val()函數(shù)中使用了備用值敦锌,那么你的代碼將更加可靠,它能在兼容性不好的瀏覽器中實(shí)現(xiàn)優(yōu)雅降級(jí)。
對(duì)于上面的代碼颈墅,在Chrome和其他支持CSS變量的瀏覽器中,<section>標(biāo)簽里的文本將是藍(lán)色:
在IE11中罪帖,由于它不支持CSS變量复隆,頁(yè)面將顯示灰色文本:
可以查看在線的示例7代碼(https://gitee.com/GrapeTech/css-variable-demo/blob/master/demo-7.html)
此方法的一個(gè)缺點(diǎn)是,如果你大量使用CSS變量讯检,而那些不支持CSS變量的瀏覽器在你的項(xiàng)目中有很高的適配優(yōu)先級(jí)琐鲁,那么相應(yīng)的代碼會(huì)變得很復(fù)雜卫旱,對(duì)于維護(hù)來(lái)說(shuō),甚至是噩夢(mèng)围段。
在這種情況下顾翼,你可以選擇使用帶有cssnext的PostCSS,它能讓你在CSS代碼中使用最新的特性奈泪,并且讓原本不支持這些屬性的瀏覽器适贸,也能運(yùn)行這些代碼(有點(diǎn)像JavaScript轉(zhuǎn)換器做的事情)。
備注:本文所有示列代碼(https://gitee.com/GrapeTech/css-variable-demo/repository/archive/master.zip)
感興趣的小伙伴涝桅,可以關(guān)注公眾號(hào)【grain先森】拜姿,回復(fù)關(guān)鍵詞 “小程序”,獲取更多資料冯遂,更多關(guān)鍵詞玩法期待你的探索~