- 原文地址:Everything you need to know about CSS Variables
- 原文作者:Ohans Emmanuel
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:MechanicianW
- 校對者:xueshuai dazhi1011
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/8fd49ecf61d72ef9a0861f68f2a7b4c95b7e72e7297d0c35ce3a44c6db7dba6a.png)
本文是我新寫的電子書的第一章(電子書目前已支援 pdf 和 mobi 格式下載)。
大多數程式語言都支援變數。然而遺憾的是,CSS 從一開始就缺乏對原生變數的支援。
你寫 CSS 嗎?如果寫的話你就知道是沒法使用變數的。當然了,除非你使用像 Sass 這樣的前處理器。
像 Sass 這樣的前處理器是把變數的使用作為一大亮點。這是一個非常好的理由去嘗試使用這類前處理器。當然了,這個理由已然足夠好了。
Web 技術發展是非常快的,在此我很高興地報告 現在 CSS 支援變數了。
然而前處理器還支援更多優秀特性,CSS 變數僅僅是其中之一。這些特性使得 Web 技術更加貼近未來。
這篇指南將向你展示變數是如何在原生 CSS 中工作的,以及怎樣使用變數讓你的程式設計工作更輕鬆。
你將學到
首先我將帶你粗略過一遍 CSS 變數的基礎知識。我相信任何理解 CSS 變數的嘗試都必須從這裡開始。
學習基礎知識是一件非常酷的事。更酷的是使用基礎知識來構建一個真正的應用。
因此,我將構建三個能夠體現 CSS 變數的使用及其易用性的專案,用這種方式把兩件事結合起來。下面是對這三個專案的快速預覽。
專案 1: 使用 CSS 變數建立一個有變化效果的元件
你可能已經構建過一個有變化效果的元件了。無論你是使用 React,Angular 還是 Vue,使用 CSS 變數都會讓構建過程更簡單。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/000be11e5e2bde713cf4f38e6cd6f517adc419b85eb43859ad0a3b5ec8f2d7b5.gif)
使用 CSS 變數建立一個有變化效果的元件。
可以在 Codepen 上檢視這個專案。
專案 2: 使用 CSS 變數實現主題定製
可能你已經看過這個專案了。我會向你展示使用 CSS 變數來定製全站主題有多麼容易。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/fd0191f5eb837bd1d5cd8d1f9ed5c3fb7727edf62fc757262a3dd80b07381308.gif)
使用 CSS 變數定製全站主題。
可以在 Codepen 上檢視這個專案。
專案 3: 構建 CSS 變數展位
這是最後一個專案了,不要在意這個專案名,我想不出更好的名字了。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/ae8bd06b4a6b376602aaab0350324d8c359dfb847226811462597c5a2fe4fe91.gif)
盒子的顏色是動態更新的。
請注意盒子的顏色是如何動態更新的,以及盒子容器是如何隨著輸入範圍值的變化進行 3D 旋轉的。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/6013babf8dd5d195e8c3fd86dc92e5e3ed187d4da7f55e9d27cc790dac87434f.gif)
這個專案展示了使用 JavaScript 更新 CSS 變數的便利性,從中你還會嚐到響應式程式設計的甜頭。
這會是非常好玩的!
花點時間在 Codepen 上玩一玩。
注意:本文假定你對 CSS 已駕輕就熟。如果你對 CSS 掌握地不是很好,或者想學習如何創作出驚豔的 UI 效果,我建議你去學習我的 CSS 進階課程(共 85 課時的付費課程)。本文內容是該課程的一個節選。?
為何變數如此重要
如果你對前處理器和原生 CSS 中的變數並不熟悉的話,以下幾個原因可以為你解答為何變數如此重要。
原因 #1:使得程式碼更可讀
無需多言,你就可以判斷出,變數使得程式碼可讀性更好,更易於維護。
原因 #2:易於在大型文件中進行修改
如果把所有的常量都維護在一個單獨檔案中,想改動某一變數時就無需在上千行程式碼間來回跳轉進行修改。
這變得非常容易,僅僅在一個地方進行修改,就搞定了。
原因 #3:定位打字錯誤更快
在多行程式碼中定位錯誤非常痛苦,更痛苦的是錯誤是由打字錯誤造成的,它們非常難定位。善於使用變數可以免除這些麻煩。
至此,可讀性和可維護性是主要優點。
感謝 CSS 變數,現在我們在原生 CSS 中也能享受到以上這些優點了。
定義 CSS 變數
先以你已經很熟悉的東西開始:JavaScript 中的變數。
JavaScript 中,一個簡單的變數宣告會像這樣:
var amAwesome;
複製程式碼
然後你像這樣可以賦值給它:
amAwesome = "awesome string"
複製程式碼
在 CSS 中,以兩個橫線開頭的“屬性”都是 CSS 變數。
/*你可以找到變數嗎? */
.block {
color: #8cacea;
--color: blue
}
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/25e4cd5f382c0c5e09caf7772391f78faf6b74d324488d9962bacbc7f845a9aa.png)
CSS 變數也被稱為“自定義屬性”。
CSS 變數作用域
還有一點需要注意。
請記住 JavaScript 中變數是有作用域的,要麼是全域性作用域
,要麼就是區域性作用域
。
CSS 變數也是如此。
思考一下下面這個例子:
:root {
--main-color: red
}
複製程式碼
:root
選擇器允許你定位到 DOM 中的最頂級元素或文件樹。
所以,這種方式宣告的變數就屬於具有全域性作用域的變數。
明白了嗎?
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/edb198d9d9c95528378042bbd4001e6ef19dcd2ec1cdeec6ecb3435fcdc88ca0.png)
區域性變數與全域性變數。
示例 1
假設你想建立一個 CSS 變數來儲存站點的主題顏色。
你會怎麼做呢?
- 建立一個作用域選擇器。通過
:root
建立一個全域性變數。
:root {
}
複製程式碼
- 定義變數
:root {
--primary-color: red
}
複製程式碼
請記住,在 CSS 中,以兩個橫線開頭的“屬性”都是 CSS 變數,比如 --color
就是這麼簡單。
使用 CSS 變數
變數一旦被定義並賦值,你就可以在屬性值內使用它了。
但是有個小問題。
如果你用過前處理器的話,一定已經習慣通過引用變數名來使用該變數了。比如:
$font-size: 20px
.test {
font-size: $font-size
}
複製程式碼
原生 CSS 變數有些不同,你需要通過 var()
函式來引用變數。
在上面這個例子中,使用 CSS 變數就應該改成這樣:
:root {
--font-size: 20px
}
.test {
font-size: var(--font-size)
}
複製程式碼
兩種寫法大不一樣。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/3c7c26daf45aacf5cca8d3a87fe3f30ea9e5a4f6a6e9d3cdde222541ba7a6cea.png)
請記得使用 var 函式。
一旦你習慣了這種方式,就會愛上 CSS 變數的。
另一個重要的注意事項是,在 Sass 這類前處理器中,你可以在任意地方使用變數,做各種計算,但是需要注意,在原生 CSS 中,你只能將變數設定為屬性值。
/*這是錯的*/
.margin {
--side: margin-top;
var(--side): 20px;
}
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/52e8362ad6f7a897c6f73028e29218732ec14736815817e585f8ad349781b18f.png)
由於屬性名非法,這段宣告會丟擲語法錯誤
CSS 變數也不能做數學計算。如果需要的話,可以通過 CSS 的 calc()
函式進行計算。接下來我們會通過示例來闡述。
/*這是錯的*/
.margin {
--space: 20px * 2;
font-size: var(--space); // 並非 40px
}
複製程式碼
如果你必須要做數學計算的話,可以像這樣使用 calc() 函式:
.margin {
--space: calc(20px * 2);
font-size: var(--space); /*等於 40px*/
}
複製程式碼
關於屬性的一些事
以下是幾個需要闡述的屬性行為:
1. 自定義屬性就是普通屬性,可以在任意元素上宣告自定義屬性
在 p,section,aside,root 元素,甚至偽元素上宣告自定義屬性,都可以執行良好。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/8b5efb2cb1d051fd2254b559de3e952b1fdec27909e23bf365996ba598b71a5c.png)
這些自定義屬性工作時與普通屬性無異。
2. CSS 變數由普通的繼承與級聯規則解析
請思考以下程式碼:
div {
--color: red;
}
div.test {
color: var(--color)
}
div.ew {
color: var(--color)
}
複製程式碼
像普通變數一樣,--color
的值會被 div 元素們繼承。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/3ab075bcf637bc0550ca828cee094b788950527a6b9713431f8fa0b306f0f011.png)
3. CSS 變數可以通過 @media
和其它條件規則變成條件式變數
和其它屬性一樣,你可以通過 @media
程式碼塊或者其它條件規則改變 CSS 變數的值。
舉個例子,以下程式碼會在大屏裝置下改變變數 gutter 的值。
:root {
--gutter: 10px
}
@media screen and (min-width: 768px) {
--gutter: 30px
}
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/95e9df65b71008738f2306311605e97452620d9bf386cf552a8408cad0983de7.png)
對於響應式設計很有用。
4. HTML 的 style 屬性中可以使用 CSS 變數。
你可以在行內樣式中設定變數值,變數依然會如期執行。
<!--HTML-->
<html style="--color: red">
<!--CSS-->
body {
color: var(--color)
}
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/10b68775b0bc493764f88842ee0fb9d086a785bcc3baa6e0128db1b2b9a869d9.png)
行內設定變數值。
要注意這一點,CSS 變數是區分大小寫的。我為了減小壓力,選擇都採用小寫形式,這件事見仁見智。
/*這是兩個不同的變數*/
:root {
--color: blue;
--COLOR: red;
}
複製程式碼
解析多重宣告
與其它屬性相同,多重宣告會按照標準的級聯規則解析。
舉個例子:
/*定義變數*/
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
/*使用變數*/
* { color: var(--color); }
複製程式碼
根據以上的變數宣告,下列元素是什麼顏色?
<p>What's my color?</p>
<div>and me?</div>
<div id='alert'>
What's my color too?
<p>color?</p>
</div>
複製程式碼
你想出答案了嗎?
第一個 p 元素顏色是 藍色
。p
選擇器上並沒有直接的顏色定義,所以它從 :root
上繼承屬性值
:root { --color: blue; }
複製程式碼
第一個 div
元素顏色是 綠色
。這個很簡單,因為有變數直接定義在 div
元素上
div { --color: green; }
複製程式碼
具有 ID 為 alert
的 div
元素顏色不是綠色,而是 紅色
#alert { --color: red; }
複製程式碼
由於有變數作用域直接是在這個 ID 上,變數所定義的值會覆蓋掉其它值。#alert
選擇器是一個更為特定的選擇器。
最後,#alert
元素內的 p
元素顏色是 紅色
這個 p 元素上並沒有變數宣告。由於 :root
宣告的顏色屬性是 藍色
,你可能會以為這個 p 元素的顏色也是 藍色
。
:root { --color: blue; }
複製程式碼
如其它屬性一樣, CSS 變數是會繼承的,因此 p 元素的顏色值繼承自它的父元素 #alert
#alert { --color: red; }
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/7634b114ed1e3b9da1446d07e4f3a06e4104f329569a277123d09e114908e4ef.png)
小測驗的答案。
解決迴圈依賴
迴圈依賴會出現在以下幾個場景中:
- 當一個變數依賴自己本身時,也就是說這個變數通過
var()
函式指向自己時。
:root {
--m: var(--m)
}
body {
margin: var(--m)
}
複製程式碼
- 兩個以上的變數互相引用。
:root {
--one: calc(var(--two) + 10px);
--two: calc(var(--one) - 10px);
}
複製程式碼
請注意不要在你的程式碼中引入迴圈依賴。
使用非法變數會怎樣?
語法錯誤機制已被廢棄,非法的 var()
會被預設替換成屬性的初始值或繼承的值。
思考一下下面這個例子:
:root { --color: 20px; }
p { background-color: red; }
p { background-color: var(--color); }
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/bdc3470ffdf666269901407d848d0020b5819a736045ea36b98d21de4c315045.png)
正如我們所料,--color
變數會在 var()
中被替換,但是替換後,屬性值 background-color: 20px
是非法的。由於 background-color
不是可繼承的屬性,屬性值將預設被替換成它的初始值即 transparent
。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/c75ec71e17843bb7723dfe2c1d45d7b607afca0f7be164bca43c7e877fe97fc6.png)
注意,如果你沒有通過變數替換,而是直接寫 background-color: 20px
的話,這個背景屬性宣告就是非法的,則使用之前的宣告定義。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/e1cb17eeb3123fe453eef28bcdf3388bdf1c6f3b144b59f7454e80863d80d1c4.png)
當你自己寫宣告時,情況就不一樣了。
使用單獨符號時要小心
當你用下面這種方式來設定屬性值時,20px
則會按照單獨符號來解析。
font-size: 20px
複製程式碼
有一個簡單的方法去理解,20px
這個值可以看作是一個單獨的 “實體”。
在使用 CSS 變數構建單獨符號時需要非常小心。
舉個例子,思考以下程式碼:
:root {
--size: 20
}
div {
font-size: var(--size)px /*這是錯的*/
}
複製程式碼
可能你會以為 font-size
的值是 20px
,那你就錯了。
瀏覽器的解釋結果是 20 px
請注意 20
後面的空格
因此,如果你必須建立單獨符號的話,請用變數來代表整個符號。比如 --size: 20px
,或者使用 calc
函式比如 calc(var(--size) * 1px)
中的 --size
就是等於 20
如果你沒看懂的話也不用擔心,在下個示例中我會解釋地更詳細。
一顆賽艇!
現在我們已經到了期待已久的章節了。
我將通過構建幾個有用的小專案,在實際應用中引導你瞭解之前所學的理論。
讓我們開始吧。
專案 1: 使用 CSS 變數建立一個有變化效果的元件
思考一下需要構建兩個不同按鈕的場景,兩個按鈕的基本樣式相同,只有些許不同。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/0d0198499f0ed6c9007f7c00878bade8e9d4a124d27aeaf354dae5f9f9740a57.gif)
這個場景中,按鈕的 background-color
和 border-color
屬性不同。
那麼你會怎麼做呢?
這裡有一個典型解決方案。
建立一個叫 .btn
的基礎類,然後加上用於變化的類。舉個例子:
<button class="btn">Hello</button>
<button class="btn red">Hello</button>
複製程式碼
.btn
包括了按鈕上的基礎樣式,如:
.btn {
padding: 2rem 4rem;
border: 2px solid black;
background: transparent;
font-size: 0.6em;
border-radius: 2px;
}
/*hover 狀態下*/
.btn:hover {
cursor: pointer;
background: black;
color: white;
}
複製程式碼
在哪裡引入變化量呢?
這裡:
/* 變化 */
.btn.red {
border-color: red
}
.btn.red:hover {
background: red
}
複製程式碼
你看到我們將程式碼複製到好幾處麼?這還不錯,但是我們可以用 CSS 變數來做的更好。
第一步是什麼?
用 CSS 變數替代變化的顏色,別忘了給變數加上預設值。
.btn {
padding: 2rem 4rem;
border: 2px solid var(--color, black);
background: transparent;
font-size: 0.6em;
border-radius: 2px;
}
/*hover 狀態下*/
.btn:hover {
cursor: pointer;
background: var(--color, black);
color: white;
}
複製程式碼
當你寫下 background: **var(--color, black)**
時,就是將背景色的值設定為變數 --color
的值,如果變數不存在的話則使用預設值 **black**
這就是設定變數預設值的方法,與在 JavaScript 和其它語言中的做法一樣。
這是使用變數的好處。
使用了變化量,就可以用下面這種方法來應用變數的新值:
.btn.red {
--color: red
}
複製程式碼
就是這麼簡單。現在當使用 .red
類時,瀏覽器注意到不同的 --color
變數值,就會立即更新按鈕的樣式了。
如果你要花很多時間來構建可複用元件的話,使用 CSS 變數是一個非常好的選擇。
這是並排比較:
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/a4902e78aa8e4436944ce3fb953953d1b80b51099e84f50921e0889958762a60.png)
不用 CSS 變數 VS 使用 CSS 變數。
如果你有非常多的可變選項的話,使用 CSS 變數還會為你節省很多打字時間。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/2fca0d1266ba6878e3a72f4581719a47e3f1730d7e667ecae50c412a302862dd.png)
看出不同了嗎??
專案 2: 使用 CSS 變數實現主題定製
我很確定你之前一定遇到過主題定製的需求。支援主題定製的站點讓使用者有了自定義的體驗,感覺站點在自己的掌控之中。
下面是我寫的一個簡單示例:
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/fd0191f5eb837bd1d5cd8d1f9ed5c3fb7727edf62fc757262a3dd80b07381308.gif)
使用 CSS 變數來實現有多麼容易呢?
我們來看看。
在此之前,我想提醒你,這個示例非常重要。通過這個示例我將引導你理解使用 JavaScript 更新 CSS 變數的思想。
非常好玩!
你會愛上它的!
我們究竟想做什麼。
CSS 變數的美在於其本質是響應式的。一旦 CSS 變數更新了,任意帶有 CSS 變數的屬性的值也都會隨之更新。
從概念上講,下面這張圖解釋了這個示例的流程。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/691d0fcb8d571a31747b4bba0e1bb6d7e61d7ef9fe9bac4f8ec1d49075b2f924.png)
流程。
因此,我們需要給點選事件監聽器寫一些 JavaScript 程式碼。
在這個簡單的示例裡,文字與頁面的顏色和背景色都是基於 CSS 變數的。
當你點選頁面上方的按鈕時,JavaScript 會將 CSS 變數中的顏色切換成別的顏色,頁面的背景色也就隨之更新。
這就是全部了。
還有一件事。
當我說 CSS 變數切換成別的顏色時,是怎麼做到的呢?
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/8479d55f131d4b4537ded3842e7080f761f438f555e85012ba455e1b75fcded5.png)
行內設定變數。
即使是在行內設定,CSS 變數也會生效。在 JavaScript 中,我們控制了文件的根節點,然後就可以在行內給 CSS 變數設定新的值了。
明白了嗎?
我們說了太多了,現在該幹些實際的了。
結構初始化
初始化結構是這樣的:
<div class="theme">
<button value="dark">dark</button>
<button value="calm">calm</button>
<button value="light">light</button>
</div>
<article>
...
</article>
複製程式碼
結構中有三個父元素為 .theme
的按鈕元素。為了看起來儘可能簡短,我將 article
元素內的內容截斷了。article
元素內就是頁面的內容。
設定頁面樣式
專案的成功始於頁面的樣式。這個技巧非常簡單。
我們設定頁面樣式的 background-color
和 color
是基於變數的,而不是寫死的屬性值。
這就是我說的:
body {
background-color: var(--bg, white);
color: var(--bg-text, black)
}
複製程式碼
這麼做的原因顯而易見。無論何時按鈕被點選,我們都會改變文件中兩個變數的值。
根據變數值的改變,頁面的整體樣式也就隨之更新。小菜一碟。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/b546ae946e1d76f30bcae2c3d6969c865ed077aac94e3157d94a78ea11920183.png)
讓我們繼續前進,解決在 JavaScript 中更新屬性值的問題。
進入 JavaScript
我將直接把這個專案所需的全部 JavaScript 展示出來。
const root = document.documentElement
const themeBtns = document.querySelectorAll('.theme > button')
themeBtns.forEach((btn) => {
btn.addEventListener('click', handleThemeUpdate)
})
function handleThemeUpdate(e) {
switch(e.target.value) {
case 'dark':
root.style.setProperty('--bg', 'black')
root.style.setProperty('--bg-text', 'white')
break
case 'calm':
root.style.setProperty('--bg', '#B3E5FC')
root.style.setProperty('--bg-text', '#37474F')
break
case 'light':
root.style.setProperty('--bg', 'white')
root.style.setProperty('--bg-text', 'black')
break
}
}
複製程式碼
不要被這段程式碼嚇到,它比你想象的要簡單。
首先,儲存一份對根節點的引用, const root = document.documentElement
這裡的根節點就是 HTML
元素。你很快就會明白為什麼這很重要。如果你很好奇的話,我可以先告訴你一點,給 CSS 變數設定新值時需要根節點。
同樣地,儲存一份對按鈕的引用, const themeBtns = document.querySelectorAll('.theme > button')
querySelectorAll
生成的資料是可以進行遍歷的類陣列結構。遍歷按鈕,然後給按鈕設定點選事件監聽。
這裡是怎麼做:
themeBtns.forEach((btn) => {
btn.addEventListener('click', handleThemeUpdate)
})
複製程式碼
handleThemeUpdate
函式去哪了?我們接下來就會討論這個函式。
每個按鈕被點選後,都會呼叫回撥函式 handleThemeUpdate
。因此知道是哪個按鈕被點選以及後續該執行什麼正確操作很重要。
鑑於此,我們使用了 switch 操作符
,基於被點選的按鈕的值來執行不同的操作。
接下來再看一遍這段 JavaScript 程式碼,你會理解地更好一些。
專案 3: 構建 CSS 變數展位
避免你錯過它,這是我們即將構建的專案:
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/ae8bd06b4a6b376602aaab0350324d8c359dfb847226811462597c5a2fe4fe91.gif)
請記住盒子的顏色是動態更新的,以及盒子容器是隨著輸入範圍值的變化進行 3D 旋轉的。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/6013babf8dd5d195e8c3fd86dc92e5e3ed187d4da7f55e9d27cc790dac87434f.gif)
你可以直接在 Codepen 上玩一下這個專案。
這是使用 JavaScript 更新 CSS 變數以及隨之而來的響應式特性的絕佳示例。
讓我們來看看如何來構建。
結構
以下是所需的元件。
- 一個範圍輸入框
- 一個裝載使用說明文字的容器
- 一個裝載盒子列表的 section,每個盒子包含輸入框
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/4411c8329c7b91d34fac5d59457fbee7344743dcbee103902f079755ee53249e.png)
結構變得很簡單。
以下就是:
<main class="booth">
<aside class="slider">
<label>Move this ? </label>
<input class="booth-slider" type="range" min="-50" max="50" value="-50" step="5"/>
</aside>
<section class="color-boxes">
<div class="color-box" id="1"><input value="red"/></div>
<div class="color-box" id="2"><input/></div>
<div class="color-box" id="3"><input/></div>
<div class="color-box" id="4"><input/></div>
<div class="color-box" id="5"><input/></div>
<div class="color-box" id="6"><input/></div>
</section>
<footer class="instructions">
?? Move the slider<br/>
?? Write any color in the red boxes
</footer>
</main>
複製程式碼
以下幾件事需要注意。
- 範圍輸入代表了從
-50
到50
範圍的值,step 值為5
。因此範圍輸入的最小值就是-50
- 如果你並不確定範圍輸入是否可以執行,可以在 w3schools 上檢查以下
- 注意類名為
.color-boxes
的 section 是如何包含其它.color-box
容器的。這些容器中包含輸入框。 - 第一個輸入框有預設值為 red。
理解了文件結構後,給它新增樣式:
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/49007c20893cd679b20508330f881380c80070fdc02afc2dd9d314fe0912f701.png)
- 把
.slider
和.instructions
設定為脫離文件流,將它們的 position 設定為 absolute - 將
body
元素的背景色設定為日出的顏色,並在左下角用花朵作裝飾 - 將
color-boxes
容器定位到中間 - 給
color-boxes
容器新增樣式
讓我們把這些任務都完成。
以下程式碼會完成第一步。
/* Slider */
.slider,
.instructions {
position: absolute;
background: rgba(0,0,0,0.4);
padding: 1rem 2rem;
border-radius: 5px
}
.slider {
right: 10px;
top: 10px;
}
.slider > * {
display: block;
}
/* Instructions */
.instructions {
text-align: center;
bottom: 0;
background: initial;
color: black;
}
複製程式碼
這段程式碼並不像你想的那般複雜。希望你能通讀一遍並能讀懂,如果沒有的話,可以留下評論或者發個 twitter。
給 body
新增樣式會涉及到更多內容,希望你足夠了解 CSS。
既然我們想用背景顏色和背景圖來設定元素的樣式,那麼使用 background
簡寫屬性設定多個背景屬性可能是最佳選擇。
就是這樣的:
body {
margin: 0;
color: rgba(255,255,255,0.9);
background: url('http://bit.ly/2FiPrRA') 0 100%/340px no-repeat, var(--primary-color);
font-family: 'Shadows Into Light Two', cursive;
}
複製程式碼
url
是向日葵圖片的連結。
接下來設定的 0 100%
代表圖片在背景中的位置。
這個插圖展示了 CSS 的 background position 屬性是如何工作的:
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/466fbfca28427e569f0c64ae1fb47112f993c9418cd6037390f8585b0633b4f7.png)
來自於: CSS 進階指南
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/6b389fc09c756e5652811a4335073fe21fca6aa134961c72b5727cad144410ca.png)
來自於: CSS 進階指南
正斜槓後面的代表 background-size
被設定為 340px
,如果將它設定得更小的話,圖片也會變得更小。
no-repeat
,你可能已經猜到它是做什麼的。它避免背景圖片自我複製,鋪滿背景。
最後,跟在逗號後面的是第二個背景屬性宣告。這一次,我們僅僅將 background-color
設定為 var(primary-color)
哇,這是個變數。
這意味著你必須定義變數。 就是這樣:
:root {
--primary-color: rgba(241,196,15 ,1)
}
複製程式碼
這裡講主題色設定為日出黃。沒什麼大問題。馬上,我們就會在這裡設定更多的變數。
現在,我們將 color-boxes
定位到中間
main.booth {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
複製程式碼
主容器充當 flex 容器,它的子元素會正確地被定位到頁面中間。也就是說我們的 color-box
容器會被定位到頁面中間。
我們把 color-boxes 以及它的子元素容器變得更好看一些。
首先,是子元素:
.color-box {
padding: 1rem 3.5rem;
margin-bottom: 0.5rem;
border: 1px solid rgba(255,255,255,0.2);
border-radius: 0.3rem;
box-shadow: 10px 10px 30px rgba(0,0,0,0.4);
}
複製程式碼
這就加上了好看的陰影,使得效果更酷炫了。
還沒結束,我們給整體的 container-boxes
容器加上樣式:
/* Color Boxes */
.color-boxes {
background: var(--secondary-color);
box-shadow: 10px 10px 30px rgba(0,0,0,0.4);
border-radius: 0.3rem;
transform: perspective(500px) rotateY( calc(var(--slider) * 1deg));
transition: transform 0.3s
}
複製程式碼
哇!
變得太複雜了。
去掉一些。
變得簡單點:
.color-boxes {
background: var(--secondary-color);
box-shadow: 10px 10px 30px rgba(0,0,0,0.4);
border-radius: 0.3rem;
}
複製程式碼
你知道效果會變成什麼樣,對吧?
這裡有個新變數,需要在根元素中宣告新增進來。
:root {
--primary-color: rgba(241,196,15 ,1);
--secondary-color: red;
}
複製程式碼
第二個顏色是紅色,我們會給容器加上紅色的背景。
接下來這部分可能會讓你覺得難以理解:
/* Color Boxes */
.color-boxes {
transform: perspective(500px) rotateY( calc(var(--slider) * 1deg));
transition: transform 0.3s
}
複製程式碼
又是我們會將 transform 的屬性值簡寫成上面這樣。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/763324e51ccc40b1701feec5a134469197eba91f1d5b8b2498bc2d4a0fe581e3.png)
舉個例子:
transform: perspective(500px) rotateY( 30deg);
複製程式碼
這個 transform 簡寫用了兩個不同的函式。一個是視角,另一個是沿著 Y 軸旋轉。
那麼 perspective
函式 和 rotateY
函式是做什麼的呢?
perspective() 函式應用於 3D 空間內旋轉的元素。它啟用了三維空間,並沿 z 軸給出元素的深度。
可以在 codrops 上閱讀更多有關 perspective 的知識。
rotateY
函式是幹什麼的?
啟用三維空間後,元素具有了 x,y,z 軸。rotateY
就是元素圍繞 Y
平面旋轉。
下面這個 codrops 的圖對於視覺化理解很有幫助。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/f0e60b8c434ee40892f821f87710181c6531b0374fb1161c7af6b7a7ab403ed8.png)
我希望這能讓你更明白一些。
回到之前的話題。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/763324e51ccc40b1701feec5a134469197eba91f1d5b8b2498bc2d4a0fe581e3.png)
當你回到這裡,你知道哪個函式影響 .container-box
的旋轉了嗎?
是 rotateY 函式使得盒子沿著 Y 周旋轉。
由於傳入 rotateY 函式的值將被 JavaScript 更新,這個值也將通過變數來傳入。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/32ec7627bca468bc7aba15b4284dec922a6c2c596ba7a5ec18d36d56eae79b3c.png)
為什麼要給變數乘上 1deg?
作為一般的經驗法則,為了顯式地更靈活,建議在構建單獨符號時變數中儲存沒有單位的值。
通過 calc
函式,你可以用乘法將它們轉化成任何單位。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/54e6a2da131d2fc87c3f9f6931e7bea59fddfa42a7206533533bc5f3587f31bd.png)
這意味著你可以為所欲為。將作為比例的 deg
轉換為視窗單位 vw
也可以。
在這個場景中,我們通過 “數字” 乘上 1deg 將數字轉換成角度
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/af29c557e0f0ae10a6a15545a1144e1d5e94d75700e41590e8ff205556b8eb8d.png)
由於 CSS 不懂數學,你需要將公式傳入 calc 函式,這樣 CSS 才能正確計算。
完成之後我們就可以繼續了。我們可以在 JavaScript 中用各種方法來更新它。
現在,只剩下一點點的 CSS 程式碼需要寫了。
就是這些:
/* 給每個盒子新增顏色 */
.color-box:nth-child(1) {
background: var(--bg-1)
}
.color-box:nth-child(2) {
background: var(--bg-2)
}
.color-box:nth-child(3) {
background: var(--bg-3)
}
.color-box:nth-child(4) {
background: var(--bg-4)
}
.color-box:nth-child(5) {
background: var(--bg-5)
}
.color-box:nth-child(6) {
background: var(--bg-6)
}
複製程式碼
這些奇怪的東西是什麼?
首先,nth-child 選擇器用來選擇子盒子。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/bfbddb3f2a190424c34ddf8f73655c5c1d6d53c674540ed7f2fcc24b4ec07ea0.png)
這裡需要一些前瞻。我們知道,每個盒子的背景色都會更新。我們也知道背景色需要用變數表示,以在 JavaScript 中更新。對吧?
接下來:
.color-box:nth-child(1) {
background: var(--bg-1)
}
複製程式碼
簡單吧。
這裡有個問題。如果變數不存在的話怎麼辦?
我們一個回退方式。
這是可行的:
.color-box:nth-child(1) {
background: var(--bg-1, red)
}
複製程式碼
在這個特殊例項中,我選擇不提供任何回退方式。
如果某個屬性值中使用的變數非法,屬性將使用其初始值。
因此,當 --bg-1
非法或者不可用時,背景色會預設切換成它的初始顏色或者透明。
初始值指向屬性還未顯式設定時的值。比如說,如果你沒有給元素設定 background-color
屬性的話,它的背景色會預設為 transparent
初始值是一種預設屬性值。
寫點 JavaScript
在 JavaScript 這一邊需要做的事情很少。
首先要處理一下 slider。
僅僅五行程式碼就可以!
const root = document.documentElement
const range = document.querySelector('.booth-slider')
// 一旦 slider 的範圍值發生變化,就執行回撥
range.addEventListener('input', handleSlider)
function handleSlider (e) {
let value = e.target.value
root.style.setProperty('--slider', value)
}
複製程式碼
這很簡單,對吧?
我來解釋一下。
首先,儲存一份 slider 元素的引用,const range = document.querySelector('.booth-slider')
設定一個事件監聽器,一旦範圍輸入值發生變化就會觸發,range.addEventListener('input', handleSlider)
寫一個回撥函式, handleSlider
function handleSlider (e) {
let value = e.target.value
root.style.setProperty('--slider', value)
}
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/aefeec5a6dbe778de8113029da2d1b0603b0ef139e7b1936b872962a6d3ef2fe.png)
root.style.setProperty('--slider', value)
的意思是獲取 root
元素(HTML),讀取它的樣式,並給它設定屬性。
處理顏色變化
這與處理 slider 值的變化一樣簡單。
這麼做就可以:
const inputs = document.querySelectorAll('.color-box > input')
// 一旦輸入值發生變化,執行回撥
inputs.forEach(input => {
input.addEventListener('input', handleInputChange)
})
function handleInputChange (e) {
let value = e.target.value
let inputId = e.target.parentNode.id
let inputBg = `--bg-${inputId}`
root.style.setProperty(inputBg, value)
}
複製程式碼
儲存一份所有文字輸入的引用, const inputs = document.querySelectorAll('.color-box > input')
給每個輸入框加上事件監聽:
inputs.forEach(input => {
input.addEventListener('input', handleInputChange)
})
複製程式碼
寫 handleInputChange
函式:
function handleInputChange (e) {
let value = e.target.value
let inputId = e.target.parentNode.id
let inputBg = `--bg-${inputId}`
root.style.setProperty(inputBg, value)
}
複製程式碼
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/5ab108cf1b1f57ebb713d1c1d448d8791022676d4be7637234f9b8ab0d1f1080.png)
嗯……
就是這些!
專案完成了。
我遺漏了什麼?
當我完成並修改了初稿後才發現我沒有提到瀏覽器支援。那讓我來處理這個爛攤子。
對於 CSS 變數的(又名自定義屬性)瀏覽器支援並不差。 瀏覽器支援性非常好,基本所有的現代瀏覽器都支援良好(本文寫作時已超過 87%)。
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/61704b55cfac2e75f6e5dccb1d0612d1268fb66a5aa05d581eaabba6eb4a3efa.png)
那麼,你可以在生產環境使用 CSS 變數嗎?當然可以!但是這多大程度上適用於你還需自己判斷。
好的一面是,你可以使用像 Myth 這樣的前處理器來使用 CSS 變數。它將“未來的” CSS 預編譯成現在你就可以使用的程式碼,是不是很贊?
如果你有使用 postCSS 的經驗, 這也同樣是一個好方法。這是 postCSS 的 CSS 變數模組。
就這些,我已全部寫完。
不好,我遇到了問題!
![[譯] 關於 CSS 變數,你需要了解的一切](https://i.iter01.com/images/2b930a8b282f0045164cc51601d635147a88b8319947c80223850fedeceeb38d.png)
購買電子書 可以線上閱讀, 還能獲得 私人的 slack 邀請,你可以向我諮詢任何問題。
這是個公平交易,對吧?
稍後聯絡! ?
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。