CSS變量實用指南及注意事項

近年來,一些動態特性已經開始成爲 CSS 語言自己的一部分。 CSS變量 – 官方的術語爲 「自定義屬性」 – 已經已經加入規範而且具備很好的瀏覽器支持,而 CSS mixins 目前正在開發中 。css

在本文中,你將瞭解如何開始將CSS變量集成到CSS開發工做流程中,讓你的樣式表更好維護,且減小重複。html

讓咱們一塊兒深刻了解吧!前端

什麼是CSS變量?編程

若是你使用過任何編程語言,那麼你已經熟悉了變量的概念。變量用於存儲和更新你的程序所須要的值,以便使它運行。設計模式

例如,請考慮如下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 是兩個變量,分別存儲着數字 2 和 3 。緩存

total 一樣是變量,存儲着 number1number2 之和。在這裏它的值就是 5。你能夠動態地修改變量裏的值,並在程序中使用它們。在上面的代碼中,我把 number1 的值更新爲 4,而後再進行求和。使用相同的變量,這個時候 total裏存儲的值就再也不是 5 ,而是 7 了。編程語言

變量的好處在於你能夠把值存儲在一個地方,而後在你須要的地方修改它。這樣你就不用在程序的不一樣地方爲不一樣的值添加不一樣的變量:全部變量更新使用同一個存儲地址,好比你的變量。ide

CSS在很大程度上是一種聲明式的語言,缺少動態性。你也許會認爲,讓 CSS 擁有變量,彷佛讓上面的說法自相矛盾。若是前端開發僅僅關注語義,那能夠這麼說。幸運的是,Web的編程語言很像生活中的語言,它們會隨着周圍環境和實踐需求而不斷進化與適應。CSS也不例外。svg

總而言之,變量已經成爲 CSS 中使人激動的實現,你很快也會發現,對於這個厲害的新技術,學習和使用起來都很是直觀。

使用CSS變量有什麼好處?

使用CSS變量的好處,跟在其餘編程語言中使用變量的好處沒什麼大的區別。

如下是規範對此的說法:

[使用CSS變量]能夠更容易地閱讀大文件,由於看似任意的值,如今具備信息性名稱,而且使此類文件更容易編輯,且更不容易出錯,由於,你只須要在自定義屬性中改變一次值,全部應用了這個變量的地方都會自動跟着一塊兒改變。W3C 規範

換句話說:

經過給變量起一個對你來講在項目中有意義的名字,你能更容易的管理和維護你的代碼。例如,當你爲項目中的主色調設置一個變量名--primary-color ,那麼你後面再修改這個主色調時,只須要改動一處,而不須要在不一樣位置的多個CSS文件中去手動屢次修改這個值。

CSS變量和預處理器中的變量有什麼不一樣?

你可能已經在CSS預處理器中嘗試過使用變量而帶來的好處了,好比 SassLess

預處理器讓你能設置變量,以及在函數、循環、數學計算等等地方中使用它們。這是否意味着CSS變量已經可有可無了呢?

那可未必,主要是由於,CSS變量與預處理器中的變量其實並非一樣的東西。

不一樣之處在於CSS變量是運行在瀏覽器中的動態CSS屬性,而預處理器變量會被編譯成普通的CSS代碼。所以,瀏覽器並不知道預處理器變量的存在。

這意味着,你能夠在樣式表,內聯樣式和SVG的標籤中直接更新CSS變量,或者使用JavaScript操做它們。這是預處理器變量作不到的。CSS變量提供了更多可能性!

但這並非說你須要在兩者之間選擇其一:沒有什麼東西限制你,你能夠同時使用CSS變量和預處理變量,並享有它們各自帶來的巨大好處。

CSS變量:語法

雖然本文爲了簡潔,我使用了CSS變量(CSS variables)這個術語,可是官方的規範把它們稱做爲 級聯變量的CSS自定義屬性。CSS自定義屬性形式以下:

--my-cool-background: #73a4f4;

在自定義屬性前面添加雙橫線前綴,而後像普通的CSS屬性同樣給它賦值。在上面的代碼片斷中,我給 --my-cool-background 自定義屬性賦了一個顏色值。

而 級聯變量(cascading variable) 的部分,由經過 var() 來使用你的自定義屬性,形式以下:

var(--my-cool-background);

自定義屬性的做用範圍限定在 CSS 選擇器中, var() 部分用做實際 CSS 屬性的值:

:root {
--my-cool-background: #73a4f4;
}
/* CSS文件的其餘部分 */
#foo {
background-color: var(--my-cool-background);
}

上面的代碼片斷把 --my-cool-background 自定義屬性的做用域定義在 :root 這個僞類中,這讓該自定義屬性能在全局可用(它匹配<html>元素內的全部內容)。而後,使用 var() 函數把 ID 爲 foo 的容器的 background-color 設置爲自定義屬性的值,這時該容器就有了淺藍的背景色。

除此以外,還能夠把淡藍色應用到多個HTML元素的其餘顏色屬性上,如 colorborder-color 等。方法很簡單,就是經過 var(--my-cool-background) 獲取自定義屬性的值,而後給相應的CSS屬性設置上去。(固然,我建議在事情變得混亂以前考慮一下CSS變量的命名約定):

p {
color: var(--my-cool-background);
}

你也能夠在CSS變量中使用另外一個CSS變量,例如:

--top-color: orange;
--bottom-color: yellow;
--my-gradient: linear-gradient(var(--top-color), var(--bottom-color));

上面的代碼建立了一個 --my-gradient 變量,是一個漸變樣式,它的值是使用 --top-color--bottom-color 變量建立的一個漸變。如今,你能夠在任何地方經過僅僅改變變量的值來修改漸變,而沒必要處處在樣式表中建立漸變實例。

最後,你能夠在CSS變量中加入一個或多個備用值,例如:

var(--main-color, #333);

上面的代碼中,#333是一個備用值。若是未設置備用值,則在自定義屬性無效或未設置的狀況下,將應用繼承的值。

CSS變量是區分大小寫的

與普通CSS屬性不一樣,CSS變量是區分大小寫的。

例如,var(--foo)var(--FOO) 是獲取兩個不一樣的自定義屬性(分別是 --foo--FOO)的值。

CSS變量受級聯關係影響

和普通CSS屬性同樣,CSS變量是可繼承的。例如,咱們定義了一個屬性,值爲 blue :

:root {
--main-color: blue;
}

當你在 <html> 標籤中的任意元素指定 --main-color 變量時,它們都會繼承到blue這個值。

若是你在另外一個元素裏面給自定義屬性賦了一個不一樣的值,這個元素的全部子元素就會繼承這個新值,例如:

CSS:

:root {
--main-color: blue;
}
.alert {
--main-color: red;
}
p {
color: var(--main-color);
}

HTML:

&lt;--! HTML --&gt;
&lt;html&gt;
&lt;head&gt;
&lt;!-- head code here --&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
&lt;p&gt;blue 的段落&lt;/p&gt;
&lt;div class="alert"&gt;
&lt;p&gt;red 的段落&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;

在上面的標籤中,第一個段落會繼承到全局的 --main-color 值,它是藍色。

在div標籤中擁有 .alert 類的段落會是紅色,由於它的值繼承自局部做用域裏的 --main-color ,這個變量的值是 red

內聯樣式中的 CSS 變量

CSS變量也能夠在元素的內聯樣式中定義。 假設您有一個能夠控制大小的組件,

你能夠看到元素的內聯樣式中一樣能夠定義CSS變量,並且一樣遵循相同的級聯規則。

var()函數

如今你知道了 var() 函數的用法。有關此功能的更多信息。 看下面的代碼,有一個紅色的 div 和一個綠色的div。只有一個CSS變量用於子綠色 div

如今從:root選擇器 刪除CSS變量 --background: green;,看看會發生什麼。

你可能猜想子元素將具備從父元素繼承的背景紅色。 錯了,這裏有點特殊狀況。 當您在任何CSS屬性中使用該變量時,若是沒有定義變量,那麼它將默認採用默認值。 在這個例子中,背景顏色將是transparent(透明的):

你可能猜想子元素將具備從父元素繼承的背景紅色。 錯了,這裏有點特殊狀況。 當您在任何CSS屬性中使用該變量時,若是沒有定義變量,那麼它將默認採用默認值。 在這個例子中,背景顏色將是transparent(透明的):

無效的值

若是CSS變量有一個無效的值,好比 --background: blah blah blah; 或拼寫錯誤 --background: yelow; /* yellow 拼寫錯誤 */,那麼 CSS 屬性將默認採用默認值,如:

background 默認值是 transparent
width 默認值是 auto
position 默認值是 static
opacity 默認值是 1
display 默認值是 inline

下面這個例子中,background的值爲transparent,也就是說背景顏色是透明的。

回退值(fallback value)

有時可能會出現沒法定義CSS變量的狀況。在這種狀況下,您能夠將回退值設置爲 var() 函數中的第二個參數

你也能夠嵌套多個var() 函數 background: var(--color1, var(--color2, var(--color3, #00BCD4)));

結合 calc()函數

若是你之前從未使用過它,那麼我如今告訴你 calc() 函數是一個很實用的小工具,可讓您執行計算以肯定CSS值。 它在全部現代瀏覽器上都獲得了很好的支持,而且能夠與 CSS變量結合使用,以構建新值。 下面的例子中 <div>width是動態計算的,

結合媒體查詢 @media

你甚至能夠在媒體查詢中從新設置變量值,並讓這些新值在任何地方使用它們級聯,特別要說明的是:這是預處理器變量沒法實現的。

查看此示例,其中媒體查詢更改用於設置很是簡單網格的變量,打開 codepen,而後嘗試調整瀏覽器的大小,你能夠看到媒體查詢中的 CSS 變量依然有效。

如今瞭解這些規則足夠,讓咱們來編碼吧!

如何在SVG中使用CSS變量

CSS變量和SVG配合得很好。你可使用CSS變量去修改SVG中的樣式,以及和呈現相關的屬性。

好比,你想經過SVG圖標元素的父元素來給它一個不一樣的顏色。你能夠在父元素內設置一個局部的CSS變量,而後把它賦值成你想要的顏色,而後,父元素內的圖標就能從父元素繼承到合適的顏色。

下面是相關代碼:

/* 圖標的內聯SVG symbol */
&lt;svg&gt;
&lt;symbol id="close-icon" viewbox="0 0 200 200"&gt;
&lt;circle cx="96" cy="96" r="88" fill="none" stroke="var(--icon-color)" stroke-width="15" /&gt;
&lt;text x="100" y="160" fill="var(--icon-color)" text-anchor="middle" style="font-size:250px;"&gt;x&lt;/text&gt;
&lt;/symbol&gt;
&lt;/svg&gt;
/* 圖標的第一個實例  */
&lt;svg&gt;
&lt;use xlink:href="#close-icon" /&gt;
&lt;/svg&gt;

上面的代碼使用了 <symbol> 標籤,它讓你建立一 SVG 圖形的不可見的版本。而後再使用 <use> 標籤生成一個可見的副本。這種方法可讓你根據本身的喜愛建立任意多個自定義的圖標,也就是經過它的ID( #close-icon )指向那個 <symbol> 。這比一遍又一遍地寫重複的代碼建立圖形更加簡便。若是你想提升這方便的技術,Massimo Cassandro在他的 創造你本身的SVG圖標 中提供了一個快速教程。

注意 SVG中的圓形元素的 stroke 屬性值和文本元素的 fill 屬性值:它們都使用了一個CSS變量,--icon-color ,這個變量定義在CSS文檔的 :root 選擇器上,以下所示: 

:root {
--icon-color: black;
}

這是當前圖標看起來的樣子:

若是你如今把SVG圖標放到不一樣的容器中,而後在每一個父元素的選擇器中給這個變量賦不一樣的顏色值,你就能在不添加任何樣式規則的狀況下建立不一樣顏色的圖標。這很酷!

爲了展現這一點,咱們把上面圖標的一個實例放在一個有 .success 類的 div 中。

HTML 代碼:

&lt;!-- html --&gt;
&lt;div class="success"&gt;
&lt;svg&gt;
&lt;use xlink:href="#close-icon" /&gt;
&lt;/svg&gt;
&lt;/div&gt;

如今,讓 --icon-color 變量局部化,即把它放在 .success 中,並設置一個 green 值。咱們來看看發生的變化:

CSS 代碼:

/* css */
.success {
--icon-color: green;
}

這個圖標的顏色就變成了綠色:

如何在@keyframes中使用CSS變量

CSS變量能夠在CSS動畫中使用,不管是在通常的HTML元素仍是內聯SVG元素上。只須要記得,你得知道讓什麼元素動,把它視爲目標元素,而後建立對該目標元素的選擇器,在選擇器的做用範圍中定義你的CSS變量,而後,使 var() 獲取這些變量,把它們設置到 @keyframes 代碼塊中。

例如,讓SVG中 .bubble 類裏面的 <ellipse> 元素動起來,你的CSS可能會看起來像這樣:

.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() 函數進行計算的。它們加強了你代碼的靈活性。

這個例子簡潔的地方在於,利用CSS屬性,你能夠簡單的修改相應選擇器裏變量值而調整動畫,而不須要挨個去查找 @keyframes 裏的屬性了。

如何經過JavaScript操做CSS變量

另外一個超級酷的事情就是,你能夠直接經過JavaScript代碼訪問CSS變量。經過 getComputedStylesetPropertygetPropertyValue從JavaScript訪問CSS變量很是簡單。 要獲取變量,請使用 getPropertyValue()

假設在你的CSS文件中,有一個叫作 --left-pos的變量,做用在 .sidebar 選擇器中,值爲 100px:

.sidebar {
--left-pos: 100px;
}

那麼,使用相似下面的 JavaScript 代碼獲取 --left-pos 的值:

// 緩存你即將操縱的元素
const sidebarElement = document.querySelector('.sidebar');
// 緩存sidebarElement的樣式於cssStyles中
const cssStyles = getComputedStyle(sidebarElement);
// 獲取 --left-pos CSS變量的值
const cssVal = String(cssStyles.getPropertyValue('--left-pos')).trim();
// 將CSS 變量的值打印到控制檯: 100px
console.log(cssVal);

使用相似下面的JavaScript代碼給CSS變量賦值:

sidebarElement.style.setProperty('--left-pos', '200px');

上面的代碼將sidebar元素中 --left-pos 變量的值設置爲 200px

請看看CodePen中的以下示例,你能夠交互式地點擊側邊欄,修改 blend mode 屬性和背景色。這些實現只用到了CSS變量和JavaScript。

還有一些簡單的方法,這裏來看看不使用 getComputedStyle(),獲取變量值:

JavaScript 代碼:

/* 從 :root 根元素獲取變量值 */
document.documentElement.style.getPropertyValue('--background');
/* 從 .block-3 元素獲取變量值 */
document.querySelector('.block-3').style.getPropertyValue('--background');

修改變量值:

/* 修改 :root 根元素的變量值 */
document.documentElement.style.setProperty('--background', '#ff0000');
/* 修改 .block-3 元素的變量值 */
document.querySelector('.block-3').style.setProperty('--background', '#ff0000');

其餘一些注意點
還有一些有趣的事情,在開發時候須要注意。

空值和空格

/* 無效的 */
--color:;
/* 有效的 */
--color: ; /* 值是空格 */

背景圖片 url()

/* 無效的 - CSS 不支持拼接*/
.logo{
--logo-url: 'logo';
background: url('assets/img/' var(--logo-url) '.png');
}
/* 無效的 - CSS bug */
.logo{
--logo-url: 'assets/img/logo.png';
background: url(var(--logo-url));
}
/* 有效的 */
.logo{
--logo-url: url('assets/img/logo.png');
background: var(--logo-url);
}

單位相關

/* 無效的 */
--width: 10;
width: var(--width)px;
/* 有效的 */
--width: 10px;
width: var(--width);
/* 有效的 */
--width: 10;
width: calc(1px * var(--width)); /* 乘以1個單位進行轉換 */
width: calc(1em * var(--width));

瀏覽器對CSS變量的支持狀況

除了IE11(它不支持CSS變量),全部主流瀏覽器都對CSS變量有全面地支持。

對於不支持CSS變量的瀏覽器,一個變通的方案是使用具備虛擬查詢條件(dummy conditional query)的 @supports代碼塊:

section {
color: gray;
}
@supports(--css: variables) {
section {
--my-color: blue;
color: var(--my-color, 'blue');
}
}

由於IE/Edge支持 @supports ,因此上面的代碼會生效。若是在var()函數中添加一個後備值,你的代碼將會更加健壯,在支持的更加很差的瀏覽器中也能優雅降級。

因此,在Chrome和其餘支持CSS變量的瀏覽器中,<section>元素內部的文本是藍色的:

在IE11中,因爲它不支持CSS變量,頁面將顯示灰色文本:

這種方式的缺點是若是你在項目中使用了大量的CSS變量,可是該項目主要經過不支持CSS變量的瀏覽器打開,那麼代碼不只會變得有點兒複雜,維護也將會是噩夢。

在這種狀況下,你能夠選擇使用支持 cssnext 的PostCSS,而後你就能夠編寫尖端的CSS代碼了,兼容不支持的瀏覽器交給PostCSS去作就能夠了,這有點兒像JavaScript的編譯器。

這裏推薦一下個人前端學習交流羣:784783012,裏面都是學習前端的,若是你想製做酷炫的網頁,想學習編程。本身整理了一份2018最全面前端學習資料,從最基礎的HTML+CSS+JS【炫酷特效,遊戲,插件封裝,設計模式】到移動端HTML5的項目實戰的學習資料都有整理

點擊:加入

相關文章
相關標籤/搜索