近年來,一些動態特性已經開始成爲 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
一樣是變量,存儲着 number1
與 number2
之和。在這裏它的值就是 5。你能夠動態地修改變量裏的值,並在程序中使用它們。在上面的代碼中,我把 number1
的值更新爲 4,而後再進行求和。使用相同的變量,這個時候 total裏存儲的值就再也不是 5 ,而是 7 了。編程語言
變量的好處在於你能夠把值存儲在一個地方,而後在你須要的地方修改它。這樣你就不用在程序的不一樣地方爲不一樣的值添加不一樣的變量:全部變量更新使用同一個存儲地址,好比你的變量。ide
CSS在很大程度上是一種聲明式的語言,缺少動態性。你也許會認爲,讓 CSS 擁有變量,彷佛讓上面的說法自相矛盾。若是前端開發僅僅關注語義,那能夠這麼說。幸運的是,Web的編程語言很像生活中的語言,它們會隨着周圍環境和實踐需求而不斷進化與適應。CSS也不例外。svg
總而言之,變量已經成爲 CSS 中使人激動的實現,你很快也會發現,對於這個厲害的新技術,學習和使用起來都很是直觀。
使用CSS變量有什麼好處?
使用CSS變量的好處,跟在其餘編程語言中使用變量的好處沒什麼大的區別。
如下是規範對此的說法:
[使用CSS變量]能夠更容易地閱讀大文件,由於看似任意的值,如今具備信息性名稱,而且使此類文件更容易編輯,且更不容易出錯,由於,你只須要在自定義屬性中改變一次值,全部應用了這個變量的地方都會自動跟着一塊兒改變。W3C 規範
換句話說:
經過給變量起一個對你來講在項目中有意義的名字,你能更容易的管理和維護你的代碼。例如,當你爲項目中的主色調設置一個變量名--primary-color ,那麼你後面再修改這個主色調時,只須要改動一處,而不須要在不一樣位置的多個CSS文件中去手動屢次修改這個值。
CSS變量和預處理器中的變量有什麼不一樣?
你可能已經在CSS預處理器中嘗試過使用變量而帶來的好處了,好比 Sass
和 Less
。
預處理器讓你能設置變量,以及在函數、循環、數學計算等等地方中使用它們。這是否意味着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元素的其餘顏色屬性上,如 color
,border-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:
<--! HTML --> <html> <head> <!-- head code here --> </head> <body> <div> <p>blue 的段落</p> <div class="alert"> <p>red 的段落</p> </div> </div> </body> </html>
在上面的標籤中,第一個段落會繼承到全局的 --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 */ <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> /* 圖標的第一個實例 */ <svg> <use xlink:href="#close-icon" /> </svg>
上面的代碼使用了 <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 代碼:
<!-- html --> <div class="success"> <svg> <use xlink:href="#close-icon" /> </svg> </div>
如今,讓 --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變量。經過 getComputedStyle
,setProperty
和 getPropertyValu
e從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的項目實戰的學習資料都有整理
點擊:加入