文章摘要: 只要屬性的值使用了CSS自定義屬性在CSS中使用已宣告的CSS自定義屬性
特別宣告:此篇文章內容來源於 @Ohans Emmanuel 的《 Everything you need to know about CSS Variables 》一文。
大多數程式語言都支援變數。但遺憾的是,CSS從一開始就缺乏對原生變數的支援。如果寫CSS的話,那是沒有變數的,除非你使用像Sass這樣的CSS處理器。
變數是Sass這樣處理器的一個非常有用的特性之一。這也是你嘗試使用的理由之一。Web技術發展是非常快速的。我很高興地告訴你,CSS現在終於支援原生的變數了。
雖然CSS處理器還支援更多的特性,但是CSS新增原生的變數是很好的。這些舉措使用Web更接近未來的技術。在這篇文章接下來的內容中,我將向你展示如何在CSS使用變數,以及如何使用它們讓你的工作變得更輕鬆。
特別宣告:爲了能讓CSS的原生變數與CSS處理器變數區分出來,我更喜歡將其稱為CSS自定義屬性。
你將學到
首先會向大家介紹CSS自定義屬性的基本知識。我相信試圖理解CSS自定義屬性都必須從這一點開始。學習CSS自定義屬性的基本知識是非常有意思的事情。其中更有趣的是,你可以在真實的專案中使用這些基本原理。
因此,我將通過三個簡單的專案來向你展示CSS自定義屬性的易用性。先來快速預覽一下這三個專案:
專案1:使用CSS自定義屬性建立元件變數
你可能在專案中已經使用到了元件變數。不管是React、Angular或者Vue中,使用CSS自定義屬性都會使這個過程變得更簡單。
專案2:使用CSS自定義屬性實現面板切換
你可能在某個地方看到過類似的效果。在這個專案中將向你展示使用CSS自定義屬性是如何簡單的為Web網站實現面板切換的效果。
專案3: 建立CSS自定義屬性展臺(Booth)
這是最後一個專案。請不要介意這個名字。說實在的,我想不出一個更好的名字了。
注意如何動態更新容器的顏色,以及如何在 input
( type="range"
)控制條的範圍內更改外部容器的3D旋轉效果。
這個專案演示了使用JavaScript更新CSS自定義屬性的便利性,以及即改即得的效果。你可以在上面示例中的 input
框中輸入任意顏色值或者拖動 range
的進度條,瀏覽對應的效果變化。
為什麼CSS自定義屬性如此重要?
如果你是第一次接觸CSS處理器中的變數或者CSS自定義屬性,那麼接下來介紹的幾個方面將告訴你為什麼CSS自定義屬性對你而言是多麼的重要。
理由1:程式碼更具可讀性
不做過多的闡述,直接告訴你,使用CSS自定義屬性可以讓你的程式碼變得更具可讀性和可維護性。
理由2:在大型專案中更易於修改
如果你將所有常量儲存在一個單獨的檔案中,那麼你想對一個變數進行更改時,不必跳過數千行程式碼。它變得很寬鬆,你可以把它放在任何一個地方。
理由3:更暴打發現輸入錯誤
通過程式碼來查詢錯誤是一件極為痛苦的事情。特別是你的錯誤是由於一個簡單輸入引起的,那就更令人惱火了。因為它是極難被人發現。CSS自定義屬性的使用將消除這些麻煩。
為此,可讀性和可維護性是CSS自定義屬性最大的優勢。
我們需要感謝 CSS自定義屬性,讓我們可以在CSS中使用原生的變數,而不再需要藉助於類似Sass這樣的CSS處理器。
定義CSS自定義屬性
我們從一些熟悉的東西開始: JavaScript中的變數 。
一個簡單的JavaScript變數可以像下面這樣來宣告:
var amAwesome;
然後你可以給它賦值,比如:
amAwesome = "awesome string"
在CSS中,一個CSS自定義屬性是以兩個破折號( --
)開始的任何名稱。
/* 你可以在這裏宣告一個CSS自定義屬性*/ .block { color: #8cacea; --color: blue; /* 可以是常規的CSS屬性,但需要以兩個破折號(`--`)開始 */ }
CSS自定義屬性作用域
還有一件事你需要注意。
請記住,在JavaScript中,變數是有作用域一說。它們可能是全域性作用域,也有可能是區域性作用域。那麼在CSS中, CSS自定義屬性也有這樣的說法 。
比如下面這個示例:
:root { --main-color: red }
:root
選擇器可以選擇到DOM元素中或 document
樹中最高頂級的元素。因此,在 :root
選擇器是宣告的CSS自定義屬性,其作用域的範圍是 全域性範圍 ,也就是全域性作用域。
明白了?
:root { --color: black; /* 全域性作用域*/ } .block { color: #8cacea; --color: blue; /* 區域性作用域;`--color`作用域是`.block`選擇器 */ }
示例
假設你想建立一個CSS自定義屬性,該自定義屬性儲存Web網站面板的主色(Primary color)。那麼你將會怎麼做呢?
你將建立選擇器範圍。使用 :root
建立一個 global
自定義屬性:
:root { }
然後宣告自定義屬性:
:root { --primary-color: red; }
請記住,CSS自定義屬性可以是任何名稱,但名稱前必須要以兩個破折號,比如 --color
。
這是不是很簡單。
使用CSS自定義屬性
一旦宣告了一個CSS自定義屬性,並給其指定了一個值,那麼你就可以在CSS的屬性值中使用它。不過使用還是有點小問題。
如果你是在CSS處理器中使用,那麼你必須在屬性值中引用這個已宣告的變數,例如:
$font-size: 20px; .test { font-size: $font-size; }
但在CSS中使用已宣告的CSS自定義屬性,和在CSS處理器中使用宣告的變數略有不同。你需要通過 var()
函式來引用已宣告的CSS自定義屬性。
比如上面的示例,在CSS中使用已宣告的CSS自定義屬性,需要像下面這樣使用:
:root { --font-size: 20px; /* 宣告一個全域性使用域的CSS自定義屬性 */ } .test { font-size: var(--font-size); /* 通過var()函式呼叫已宣告的CSS自定義屬性--font-size */ }
一旦你理解了這一點,你就會開始喜歡CSS自定義屬性,而且會很喜歡。
不過需要特別注意的是, CSS自定義屬性不像Sass(或其他CSS處理器)中的變數,可以在許多地方使用變數,並且可以進行一些數學運算,但使用CSS自定義屬性時,只能在CSS屬性值中使用CSS自定義屬性 。
/* 這是一種錯誤的使用方式 */ .margin { --side: margin-top; var(--size): 20px; }
也不能像Sass這樣的處理器一樣直接做一些數學計算。如果你需要做一些資料計算,需要使用CSS的 calc()
函式。我們將在後續的示例中會聊到這一點。
/* 這是一種錯誤的使用方式 */ .margin { --space: 20px * 2; font-size: var(--space); }
使用CSS自定義屬性要做一些數學計算時,應該像下面這樣通過 calc()
函式來完成:
.margin { --space: calc(20px * 2); font-size: var(--space); }
值得注意的地方
以下幾個點是值得一提的地方。
自定義屬性是普通屬性,可以在任意元素上宣告它們
CSS自定義屬性可以在任意元素上,比如 p
、 section
、 aside
、根元素,甚至是偽元素上宣告。他們都會按照預期進行工作。
p { --color: blue; } section { --color: #bad; } aside { --color: yellow; } :root { --color: teal; } p:before { --color: red; }
當你在對應的元素中呼叫相應的CSS自定義屬性時,可以看到他們都能按照你的預期工作:
CSS自定義屬性可以通過繼承和級聯規則來解決
比如下面這段示例程式碼:
div { --color: red; } div.test { color: var(--color) } div.ew { color: var(--color) }
和正常變數一樣, --color
將會繼承 div
中的值:
CSS自定義屬性可以通過 @media
和其他條件規則來實現
和其他屬性一樣,可以在 @media
或 其他條件規則 中更改CSS自定義屬性的值。
比如下面這段示例程式碼,在較大的螢幕裝置上將會改變 gutter
的值:
:root { --gutter: 10px; } @media screen and (min-width: 768px) { --gutter: 30px; }
CSS自定義屬性可以用在HTML元素的 style
屬性中
你可以選擇在內聯樣式中宣告CSS自定義屬性,它同樣是可以按照你的預期進行工作。
body { color: var(--color) }
值得一提的是: CSS自定義屬性是區分大小寫的 。這一點需要特別的注意。
/* 這是兩個不同的CSS自定義屬性 */ :root { --color: blue; --COLOR: red; }
解決多個宣告的CSS自定義屬性
CSS自定義屬性和其他CSS屬性一樣,可以用標準級聯解決多個相同宣告的CSS自定義屬性。比如下面這個示例:
/* 宣告相同名稱的CSS自定義屬性 */ :root { --color: blue; } div { --color: green; } #alert { --color: red; } /* 使用CSS自定義屬性 */ * { color: var(--color); }
就上面宣告的CSS自定義屬性,下列元素的文字顏色將會是什麼顏色呢?
What's my color?
and me?What's my color too?color?
你能基於上述的知識點猜出來結果嗎?
第一個
元素是 blue
。因為在 p
選擇器上沒有顯式定義 --color
,所以它將繼承來自 :root
中的 --color
的值。
:root { --color: blue; }
第一個
green
。這一點非常的明顯,因為在 div
選擇器上顯示的宣告了 --color
自定義屬性的值為 green
:
div { --color: green; }
ID名為 #alert
的 div
元素,它的顏色不再是 green
,將會是 red
,那是因為在 #alert
選擇器中也顯式的宣告了 --color
的值為 red
:
#alert { --color: red; }
該ID選擇器直接宣告了一個自定義屬性的作用域,其定義的值將會覆蓋前面 div
宣告的自定義屬性,那是因為 #alert
選擇器的權重高於 div
選擇器。
由於最後一個
元素在 #alert
內,所以它的顏色也將是 red
。
在 p
元素上沒有顯式宣告CSS自定義屬性,但在 :root
元素上顯式的宣告了,因為正如你所期望的一樣,其顏色為 blue
。
:root { --color: blue; }
但CSS自定義屬性和CSS中的其他屬性是類似的,也具有繼承這樣的特性。所以最後一個
元素會繼承其父元素 #alert
中宣告的CSS自定義屬性值:
#alert { --color: red; }
解決迴圈依賴
迴圈依賴的發生方式如下。
當一個變數依賴於它自己。也就是說,它使用的是引用自身的 var()
。
:root { --m: var(--m) } body { margin: var(--m) }
另外一種方式就是兩個或多個變數相互引用時:
:root { --one: calc(var(--two) + 10px); --two: calc(var(--one) - 10px); }
目前唯一可破的方法是: 不要在程式碼中建立具有迴圈依賴關係的CSS自定義屬性 。
無效的CSS自定義屬性將會發生什麼?
如果是語法錯誤,將會直接視為無效,但無效的 var()
將會被該屬性的初始值或繼承值替代。比如下面的示例:
:root { --color: 20px; } p { background-color: red; } p { background-color: var(--color); /* 設定了一個無效的顏色值 */ }
如你所預期的一樣, --color
被 var()
替換了,但是屬性值 background-color:20px
是一個無效值。由於 background-color
不是一個可繼承的屬性,所以該值將預設為 background-color
的初值值 transparent
。
請注意,如果你已經寫了 background-color: 20px
沒有自定認屬性來替換,那麼 background-clor
將是無效的。要是前面有對應的宣告,將會使用前面的宣告。
在構建單個指令時要小心
當你設定如下所示的屬性值時, 20px
被解釋為單個指令(Tokens)。
font-size: 20px
一個簡單的方法是, 20px
的值被視為一個單獨的實體。在使用CSS自定義屬性構建單個指令時,需要特別的小心。比如下面這段示例程式碼:
:root { --size: 20 } div { font-size: var(--size)px /* 錯誤使用 */ }
你可能已經預料到 font-size
的值會產生 20px
,但這是錯誤的使用方式。瀏覽器會將其解釋為 20 px
。 注意 20
和 px
之間有一個空格 。
因此,如果你必須建立單個指令,則用一個CSS自定義屬性來表示整個指令,比如 --size:20px
或者使用 calc()
函式,比如 calc(var(--size) * 1px)
(當 --size
設定為 20
時)。
如果你對這一點不怎麼理解,沒關係,在接下來的示例中會詳細的解釋這部分內容。
我們來動手做點東西
這是我們這篇文章中一直期待的一部分。將能過構建一些有用的專案來實踐前面所討論到的相關概念。還等什麼呢?我們開始吧。
使用CSS自定義屬性建立元件變數
假設我們要建立兩個不同的按鈕。這兩個按鈕的樣式基本相同,只是略有一些細節不一樣。
在這個示例中,只有 background-color
和 border-color
樣式不同。如果你來做,你將會怎麼做呢?這就是典型的解決方案。
建立一個基類,比如說 .btn
並新增變化的類。這個示例的結構如下:
.btn
基類涵蓋了按鈕的基本樣式。比如:
.btn { padding: 2rem 4rem; border: 2px solid black; background: transparent; font-size: 0.6em; border-radius: 2px; } .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; } .btn:hover { cursor: pointer; background: var(--color, black); color: white; }
當你設定 background:var(--color,black)
時,其意思就是 background
的值是CSS自定義屬性 --color
的值。當 --color
不存在時,就會使用其預設值 black
。
這就是給CSS自定義屬性設定預設值的方法。就像JavaScript或其他程式語言一樣。這樣使用是很有意義的。
對於有差異的按鈕,你只需要像下面這樣提供CSS自定義屬性的新值就可以:
.btn.red { --color: red }
這就是兩個按鈕所有的樣式程式碼。現在,當你使用 .red
類名時,瀏覽器會解析出不同的顏色值,並立即更新按鈕的樣式效果。
如果你花大量時間構建可重用的元件,像這樣使用CSS自定義屬性就會很方便。來看看他們之間對比的截圖:
如果在你的元件庫中,還有其他風格的按鈕效果,使用CSS自定義屬性,你就可以省去很多額外的時間:
使用CSS自定義屬性切換Web站點的面板
切換Web網站的面板效果,我想你以前肯定有碰到過。比如像下面這樣的效果:
那麼這樣的一個效果,使用CSS自定義屬效能有多簡單呢?我們來一起看看。
在此之前,我想先提一下,這個例子非常的重要。在這個示例中,將會涉及到使用JavaScript更新CSS自定義屬性的一個方法。
我們真正想做的
CSS自定義屬性美妙之處在於它們的響應性。一旦它們被更新,只要屬性的值使用了CSS自定義屬性,就將會被更新。
從概念上講,下面這張圖,能很好的解釋整個過程。
因此,需要通過JavaScript給按鈕新增點選事件的監聽。
對於這個簡單的示例,都是基於CSS自定義屬性來對整個頁面的背景顏色和文字顏色做切換。也就是說,當用戶點選上面的任一按鈕時,他們將CSS自定義屬性設定為其他顏色。因此,頁面的背景顏色和文字顏色會做相應的變化,從而實現切換面板的效果。
模板結構
頁面所需的模板結果如下:
...
在 .theme
容器中包含了三個 button
。另外爲了節約篇幅,把 article
元素中的內容省略了。
頁面樣式
這個專案的成功之處就是頁面的樣式。而其中的訣竅又很簡單。我們沒有直接設定 background-color
和 color
的值,而是基於CSS自定義屬性來給他們設定屬性值。下面就是我想要表達的意思:
body { background-color: var(--bg, white); color: var(--bg-text, black) }
要實現切換面板的效果,原因很簡單。每當單擊一個按鈕時,將要更改 body
中對應的兩個CSS自定義屬性的值。在更改之後,頁面的整體樣式將被更新。是不是非常的簡單。
接下來,我們看看怎麼通過JavaScript來實現CSS自定義屬性值的更新。
新增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 } }
看到上面這一坨JavaScript程式碼,千萬別嚇到你。事實上這比你想像的要簡單得多。
首先,通過 const root = document.documentElement
來獲取根元素。這裏的根元素指的就是 元素。明白這一點是非常重要的。如果你感到好奇,這並奇怪,因為它需要設定CSS自定義屬性的新值。
同樣的,可以通過 const themeBtns = document.querySelectorAll('.theme > button')
選到 .theme
元素下的所有 button
元素。 querySelectorAll
會生成一個類似陣列的數據結構,需要對這個陣列進行迴圈遍歷。遍歷每個按鈕,並給其新增一個單擊事件監聽器。具體方法如下:
themeBtns.forEach((btn) => { btn.addEventListener('click', handleThemeUpdate) })
接下來我們解釋一下 handleThemeUpdate
函式。每個按鈕補點選時都會有一個 handleThemeUpdate
作為它的回撥函式。注意,什麼按鈕被點選,然後執行正確的操作變得非常重要。
在此基礎上,使用了一個 operator
開關器,並根據被單擊的按鈕的值執行一些操作。現在你再看一下JavaScript程式碼,你就能很輕易的理解它了。
構建CSS自定義屬性展臺
接下來我們將要構建一個CSS自定義屬性展臺:
記住,盒子的顏色是動態更新的,並且盒子的容器在三維空間中旋轉,而且是隨著 range
輸入的值做想應的角度旋轉:
你可以在文章前面的示例中體驗一下案例的效果。這是使用JavaScript更新CSS自定義屬性的典型案例之一。
接下來,咱們一起看看這個案例是怎麼實現的。
模板結構
以下是所需的元件:
- 一個
range
的輸入框 - 存放指令的容器
- 包含其他輸入框的容器,以及每個輸入框所包含的輸入欄位
結構很簡單:
有幾個方面需要注意:
-
input type=range
的值的範圍是-50
到50
,每次移動的值是5
,其最小輸入值為-50
- 如果你不確定這個
range
輸入是如何工作的,可以先查閱相關的文件 - 請注意如何使用
.color-boxes
和.color-box
容器類名,在這些容器中存在input
- 值得一提的是,第一個
input
的預設值是red
瞭解了文件的結構之後,就可以這樣做了:
- 將
.slider
和.instructions
容器設定為絕對定位,讓其脫離文件流 - 給
body
元素設定一個background-color
,並且在其左下角新增一個花的背景圖 - 將
.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; }
程式碼並不像你想像的那麼複雜。我希望你能理解它。如果你不理解上面的程式碼,那麼你可以通過下面的評論與我一起交流和討論。
對於 body
的效果需要更多的程式碼。由於我們使用 background-color
和 background-image
來給 body
設定樣式。所以使用 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-size
的值。如果你把這個值縮小,那麼背景影象也會相應的縮小。 no-repeat
你可能知道其意思。它用來防止背景影象不重複鋪滿 body
元素。最後,逗號後面的任何東西都是用來宣告第二個背景的。在我們這個示例中,第二個背景只設置了一個背景顏色,而且其值是 var(--primary-color)
。
你一看就知道,它就是一個CSS自定義屬性。這也意味著你必須先宣告這個CSS自定義屬性。比如:
:root { --primary-color: rgba(241,196,15 ,1) }
--primary-color
的原值是 yellow
。這沒什麼大不了的,接下來我們很快會在那裏設定更多的CSS自定義屬性。現在我們要做的是將 .color-boxes
放到頁面的正中間:
main.booth { min-height: 100vh; display: flex; justify-content: center; align-items: center; }
main
容器是一個Flex容器,並正確地將其子元素設定到頁面的正中心位置。另外再把 .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); }
設定了一個陰影效果。效果看上去有一些酷酷的感覺。咱們繼續給 .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; }
你知道這是什麼嗎?在這裏有一個新的CSS自定義屬性,我們應該將其新增到 :root
選擇器中。
:root { --primary-color: rgba(241,196,15 ,1); --secondary-color: red; }
第二種顏色是 red
。這將給容器設定一個 red
背景色。
接下來的程式碼可能會讓部分同學感到困惑:
.color-boxes { transform: perspective(500px) rotateY( calc(var(--slider) * 1deg)); transition: transform 0.3s }
暫時,我們可以簡化上面的 transform
屬性的值。
例如:
transform: perspective(500px) rotateY( 30deg);
transform
使用了兩個不同的函式。一個是 perspective()
,另一個是 rotateY()
。那麼這兩個函式有什麼作用呢?
perspective()
函式應用於3D空間中被變換的函式。它將啟用三維空間,並在 z
軸上賦予元素深度。
有關於 perspective()
這方面更多的資料,你可以點選 這裏 或這裏進行了解。
rotateY()
函式又是怎麼一回事呢?通過 perspective()
函式啟用的三維空間中,元素有 x
、 y
、 z
等平面,其中 rotateY()
函式會讓元素沿著 y
平面旋轉。
下圖來自於 codrops 的圖,能更好的幫助你理解這方面相關的知識。
有關於 transform
方面更多的介紹,可以點選這裏進行了解。
我希望這些能幫助你消除一些壓力。那我們回到開始的地方吧。
當你移動滑塊時,你知道什麼函式會影響 .container-box
的旋轉嗎?
它會被呼叫的 rotateY()
函式,讓這個盒子沿著 Y
軸旋轉。由於傳入 rotateY()
函式的值將是通過JavaScript來更新,因此它的值應該用一個CSS自定義屬性來表示。
那麼為什麼用 1deg
乘以這個CSS自定義屬性呢?
從經驗上來說,建議構建單一的指令時,將值儲存在沒有帶單位的CSS自定義屬性中。然後通過 calc()
函式將它們轉換成任何你想要的單位。
當你有這些值的時候,你可以用這些值做任何你想做的事情。想要轉換成 deg
或 vw
,你都可以任意選擇。
在這種情況下,通過將 number
值乘以 1deg
來把數字轉換成帶有單位的值。
由於CSS是不理解數學計算的,所以你必須通過 calc()
函式來完成。一旦完成,我們就變得容易多了。這個變數的值可以在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自定義屬性來表示,所以它可以通過JavaScript來訪問。對吧。
因此,我們可以這樣做:
.color-box:nth-child(1) { background: var(--bg-1) }
非常容易的一件事。不過有一個問題。如果這個變數不存在,又會發生什麼呢?根據前面介紹的內容,針對這一問題,我們需要做一個降級處理。就是新增一個預設顏色,比如像下面這樣:
.color-box:nth-child(1) { background: var(--bg-1, red) }
在這個特殊的案例中,我選擇不提供任何的降級處理。
如果在屬性值中使用CSS自定義屬性無效,則該屬性將接受其初始值。這一點前面已經提到過了。因此,當 --bg-1
無效或不可用時, background
將預設為其初始值 transparent
.
初始值是指當屬性沒有顯式設定時的值。例如,如果不設定元素的背景顏色,它將預設為 transparent
。初始值是一種預設的屬性值。
加入一些JavaScript程式碼
對於JavaScript程式碼,我們要做的事情會很少。
首先讓我們來處理滑塊。僅只需要五行程式碼就可以了。
const root = document.documentElement const range = document.querySelector('.booth-slider') range.addEventListener('input', handleSlider) function handleSlider (e) { let value = e.target.value root.style.setProperty('--slider', value) }
這對你而言是不是很簡單,對吧。
首先,通過 const range = document.querySelector('.booth-slider')
選到了滑塊元素。然後使用 range.addEventListener('input', handleSlider)
給 input
元素新增一個監聽事件,當 input
的範圍值得到改變時,將會呼叫 handleSlider
回撥函式。
接下來做的就是編寫 handleSlider
回撥函式:
function handleSlider (e) { let value = e.target.value root.style.setProperty('--slider', value) }
root.style.setProperty('--slider', value)
的意思是獲取根元素的 style
樣式,然後設定其屬性值。
處理顏色變化
就像處理滑塊值的變化一樣簡單。
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')
獲取所有 input
元素。然後給所有 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自定義屬性的支援時,我已經完成了這篇文章的初稿。現在也該來收拾一下相應的殘局了。
瀏覽器對CSS自定義屬性的支援並不壞。可以說相當的不錯,到目前為止所有的現代瀏覽器中都對CSS自定義屬性做了良好的支援。在寫這篇文章的時候,已經超過87%了。
那麼問題來了,我現在可以在專案中使用CSS自定義屬性了?我的回答是的!不過,一定要檢查一下你自己的使用者群體。
值得慶幸的是,你可以使用 Myth 這樣的處理器。它將把一些CSS未來的特性做了相應的處理。言外之意,還未支援的CSS特性,你現在就可以使用,聽起來是不是很爽。難道不是嗎?
如果你有使用 PostCSS 的經驗,那麼這同樣是使用未來CSS的一個很好的方法。這裏有一個 CSS自定義屬性的PostCSS模組 。
如果你從未接觸過PostCSS相關的東西,那麼你有必要花點時間去了解或者學習一下了。
那今天就到這裏吧。這就是我要和大家聊的東西,有關於CSS自定義屬性,應該掌握的一些知識點。
大漠
常用暱稱「大漠」,W3CPlus創始人,目前就職於手淘。對HTML5、CSS3和Sass等前端指令碼語言有非常深入的認識和豐富的實踐經驗,尤其專注對CSS3的研究,是國內最早研究和使用CSS3技術的一批人。CSS3、Sass和Drupal中國佈道者。2014年出版《 圖解CSS3:核心技術與案例實戰 》。
如需轉載,煩請註明出處: https://www.w3cplus.com/css/everything-you-need-to-know-about-css-variables.html