1. 程式人生 > >CSS變量實用指南及註意事項

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

指南 enc middle 特殊情況 圓形 前綴 不同之處 由於 sca

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

在本文中,你將了解如何開始將CSS變量集成到CSS開發工作流程中,讓你的樣式表更好維護,且減少重復。

讓我們一起深入了解吧!

什麽是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 了。

變量的好處在於你可以把值存儲在一個地方,然後在你需要的地方修改它。這樣你就不用在程序的不同地方為不同的值添加不同的變量:所有變量更新使用同一個存儲地址,比如你的變量。

CSS在很大程度上是一種聲明式的語言,缺乏動態性。你也許會認為,讓 CSS 擁有變量,似乎讓上面的說法自相矛盾。如果前端開發僅僅關註語義,那可以這麽說。幸運的是,Web的編程語言很像生活中的語言,它們會隨著周圍環境和實踐需求而不斷進化與適應。CSS也不例外。

總而言之,變量已經成為 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的項目實戰的學習資料都有整理

點擊:加入

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