- 原文地址:Everything you need to know about CSS Variables
- 原文作者:Ohans Emmanuel
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:MechanicianW
- 校對者:xueshuai dazhi1011
本文是我新寫的電子書的第一章(電子書目前已支援 pdf 和 mobi 格式下載)。
大多數程式語言都支援變數。然而遺憾的是,CSS 從一開始就缺乏對原生變數的支援。
你寫 CSS 嗎?如果寫的話你就知道是沒法使用變數的。當然了,除非你使用像 Sass 這樣的前處理器。
像 Sass 這樣的前處理器是把變數的使用作為一大亮點。這是一個非常好的理由去嘗試使用這類前處理器。當然了,這個理由已然足夠好了。
Web 技術發展是非常快的,在此我很高興地報告 現在 CSS 支援變數了。
然而前處理器還支援更多優秀特性,CSS 變數僅僅是其中之一。這些特性使得 Web 技術更加貼近未來。
這篇指南將向你展示變數是如何在原生 CSS 中工作的,以及怎樣使用變數讓你的程式設計工作更輕鬆。
你將學到
首先我將帶你粗略過一遍 CSS 變數的基礎知識。我相信任何理解 CSS 變數的嘗試都必須從這裡開始。
學習基礎知識是一件非常酷的事。更酷的是使用基礎知識來構建一個真正的應用。
因此,我將構建三個能夠體現 CSS 變數的使用及其易用性的專案,用這種方式把兩件事結合起來。下面是對這三個專案的快速預覽。
專案 1: 使用 CSS 變數建立一個有變化效果的元件
你可能已經構建過一個有變化效果的元件了。無論你是使用 React,Angular 還是 Vue,使用 CSS 變數都會讓構建過程更簡單。
使用 CSS 變數建立一個有變化效果的元件。
可以在 Codepen 上檢視這個專案。
專案 2: 使用 CSS 變數實現主題定製
可能你已經看過這個專案了。我會向你展示使用 CSS 變數來定製全站主題有多麼容易。
使用 CSS 變數定製全站主題。
可以在 Codepen 上檢視這個專案。
專案 3: 構建 CSS 變數展位
這是最後一個專案了,不要在意這個專案名,我想不出更好的名字了。
盒子的顏色是動態更新的。
請注意盒子的顏色是如何動態更新的,以及盒子容器是如何隨著輸入範圍值的變化進行 3D 旋轉的。
.這個專案展示了使用 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 變數也被稱為“自定義屬性”。
CSS 變數作用域
還有一點需要注意。
請記住 JavaScript 中變數是有作用域的,要麼是全域性作用域
,要麼就是區域性作用域
。
CSS 變數也是如此。
思考一下下面這個例子:
:root {
--main-color: red
}
複製程式碼
:root
選擇器允許你定位到 DOM 中的最頂級元素或文件樹。
所以,這種方式宣告的變數就屬於具有全域性作用域的變數。
明白了嗎?
區域性變數與全域性變數。
示例 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)
}
複製程式碼
兩種寫法大不一樣。
請記得使用 var 函式。
一旦你習慣了這種方式,就會愛上 CSS 變數的。
另一個重要的注意事項是,在 Sass 這類前處理器中,你可以在任意地方使用變數,做各種計算,但是需要注意,在原生 CSS 中,你只能將變數設定為屬性值。
/*這是錯的*/
.margin {
--side: margin-top;
var(--side): 20px;
}
複製程式碼
由於屬性名非法,這段宣告會丟擲語法錯誤
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 元素,甚至偽元素上宣告自定義屬性,都可以執行良好。
這些自定義屬性工作時與普通屬性無異。
2. CSS 變數由普通的繼承與級聯規則解析
請思考以下程式碼:
div {
--color: red;
}
div.test {
color: var(--color)
}
div.ew {
color: var(--color)
}
複製程式碼
像普通變數一樣,--color
的值會被 div 元素們繼承。
3. CSS 變數可以通過 @media
和其它條件規則變成條件式變數
和其它屬性一樣,你可以通過 @media
程式碼塊或者其它條件規則改變 CSS 變數的值。
舉個例子,以下程式碼會在大屏裝置下改變變數 gutter 的值。
:root {
--gutter: 10px
}
@media screen and (min-width: 768px) {
--gutter: 30px
}
複製程式碼
對於響應式設計很有用。
4. HTML 的 style 屬性中可以使用 CSS 變數。
你可以在行內樣式中設定變數值,變數依然會如期執行。
<!--HTML-->
<html style="--color: red">
<!--CSS-->
body {
color: var(--color)
}
複製程式碼
行內設定變數值。
要注意這一點,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; }
複製程式碼
小測驗的答案。
解決迴圈依賴
迴圈依賴會出現在以下幾個場景中:
- 當一個變數依賴自己本身時,也就是說這個變數通過
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); }
複製程式碼
正如我們所料,--color
變數會在 var()
中被替換,但是替換後,屬性值 background-color: 20px
是非法的。由於 background-color
不是可繼承的屬性,屬性值將預設被替換成它的初始值即 transparent
。
注意,如果你沒有通過變數替換,而是直接寫 background-color: 20px
的話,這個背景屬性宣告就是非法的,則使用之前的宣告定義。
當你自己寫宣告時,情況就不一樣了。
使用單獨符號時要小心
當你用下面這種方式來設定屬性值時,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 變數建立一個有變化效果的元件
思考一下需要構建兩個不同按鈕的場景,兩個按鈕的基本樣式相同,只有些許不同。
這個場景中,按鈕的 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 變數 VS 使用 CSS 變數。
如果你有非常多的可變選項的話,使用 CSS 變數還會為你節省很多打字時間。
看出不同了嗎??
專案 2: 使用 CSS 變數實現主題定製
我很確定你之前一定遇到過主題定製的需求。支援主題定製的站點讓使用者有了自定義的體驗,感覺站點在自己的掌控之中。
下面是我寫的一個簡單示例:
使用 CSS 變數來實現有多麼容易呢?
我們來看看。
在此之前,我想提醒你,這個示例非常重要。通過這個示例我將引導你理解使用 JavaScript 更新 CSS 變數的思想。
非常好玩!
你會愛上它的!
我們究竟想做什麼。
CSS 變數的美在於其本質是響應式的。一旦 CSS 變數更新了,任意帶有 CSS 變數的屬性的值也都會隨之更新。
從概念上講,下面這張圖解釋了這個示例的流程。
流程。
因此,我們需要給點選事件監聽器寫一些 JavaScript 程式碼。
在這個簡單的示例裡,文字與頁面的顏色和背景色都是基於 CSS 變數的。
當你點選頁面上方的按鈕時,JavaScript 會將 CSS 變數中的顏色切換成別的顏色,頁面的背景色也就隨之更新。
這就是全部了。
還有一件事。
當我說 CSS 變數切換成別的顏色時,是怎麼做到的呢?
行內設定變數。
即使是在行內設定,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)
}
複製程式碼
這麼做的原因顯而易見。無論何時按鈕被點選,我們都會改變文件中兩個變數的值。
根據變數值的改變,頁面的整體樣式也就隨之更新。小菜一碟。
讓我們繼續前進,解決在 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 變數展位
避免你錯過它,這是我們即將構建的專案:
請記住盒子的顏色是動態更新的,以及盒子容器是隨著輸入範圍值的變化進行 3D 旋轉的。
你可以直接在 Codepen 上玩一下這個專案。
這是使用 JavaScript 更新 CSS 變數以及隨之而來的響應式特性的絕佳示例。
讓我們來看看如何來構建。
結構
以下是所需的元件。
- 一個範圍輸入框
- 一個裝載使用說明文字的容器
- 一個裝載盒子列表的 section,每個盒子包含輸入框
結構變得很簡單。
以下就是:
<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。
理解了文件結構後,給它新增樣式:
- 把
.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 進階指南
來自於: 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 的屬性值簡寫成上面這樣。
舉個例子:
transform: perspective(500px) rotateY( 30deg);
複製程式碼
這個 transform 簡寫用了兩個不同的函式。一個是視角,另一個是沿著 Y 軸旋轉。
那麼 perspective
函式 和 rotateY
函式是做什麼的呢?
perspective() 函式應用於 3D 空間內旋轉的元素。它啟用了三維空間,並沿 z 軸給出元素的深度。
可以在 codrops 上閱讀更多有關 perspective 的知識。
rotateY
函式是幹什麼的?
啟用三維空間後,元素具有了 x,y,z 軸。rotateY
就是元素圍繞 Y
平面旋轉。
下面這個 codrops 的圖對於視覺化理解很有幫助。
我希望這能讓你更明白一些。
回到之前的話題。
當你回到這裡,你知道哪個函式影響 .container-box
的旋轉了嗎?
是 rotateY 函式使得盒子沿著 Y 周旋轉。
由於傳入 rotateY 函式的值將被 JavaScript 更新,這個值也將通過變數來傳入。
為什麼要給變數乘上 1deg?
作為一般的經驗法則,為了顯式地更靈活,建議在構建單獨符號時變數中儲存沒有單位的值。
通過 calc
函式,你可以用乘法將它們轉化成任何單位。
這意味著你可以為所欲為。將作為比例的 deg
轉換為視窗單位 vw
也可以。
在這個場景中,我們通過 “數字” 乘上 1deg 將數字轉換成角度
由於 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 選擇器用來選擇子盒子。
這裡需要一些前瞻。我們知道,每個盒子的背景色都會更新。我們也知道背景色需要用變數表示,以在 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)
}
複製程式碼
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 變數的(又名自定義屬性)瀏覽器支援並不差。 瀏覽器支援性非常好,基本所有的現代瀏覽器都支援良好(本文寫作時已超過 87%)。
那麼,你可以在生產環境使用 CSS 變數嗎?當然可以!但是這多大程度上適用於你還需自己判斷。
好的一面是,你可以使用像 Myth 這樣的前處理器來使用 CSS 變數。它將“未來的” CSS 預編譯成現在你就可以使用的程式碼,是不是很贊?
如果你有使用 postCSS 的經驗, 這也同樣是一個好方法。這是 postCSS 的 CSS 變數模組。
就這些,我已全部寫完。
不好,我遇到了問題!
購買電子書 可以線上閱讀, 還能獲得 私人的 slack 邀請,你可以向我諮詢任何問題。
這是個公平交易,對吧?
稍後聯絡! ?
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。