天天看點

巧用CSS變量 武漢重慶成都雲南貴州

大家了解一下CSS變量,介紹一下CSS變量的用法,看看如何巧用CSS變量,讓你的CSS變得更心動,讓你的項目更加炫酷!

CSS變量又叫CSS自定義屬性,為什麼會突然提起這個很少人用到的東西呢?因為最近在重構個人官網,不知道為什麼突然喜歡用上CSS變量,可能其自身隐藏的魅力,讓筆者對它刮目相看。

談到為什麼會在CSS中使用變量,下面舉個栗子,估計大家一看就會明白。

/* 不使用CSS變量 */

.title {

background-color: red;

}

.desc {

/* 使用CSS變量 */

:root {

--bg-color: red;

background-color: var(--bg-color);

看完可能會覺得使用CSS變量的代碼量多了一點,但是有沒有想到突然某天萬惡的策劃小哥哥和設計小姐姐說要做一個換膚功能。按照平常的思路,估計有些同學就會按照預設顔色主題增加一份對照的新顔色主題CSS檔案。這樣每次新增需求都同時維護幾套主題顔色多麻煩啊。

此時CSS變量就派上用場了,提前跟設計小姐姐規範好各種需要變換的顔色并通過CSS變量進行定義,通過JS批量操作這些定義好的CSS變量即可。這也是變換主題顔色的一種解決方案之一,好處在于隻需寫一套CSS代碼。

1

2

3

4

["red", "blue", "green"].forEach(v => {

const btn = document.getElementById(`${v}-theme-btn`);

btn.addEventListener("click", () => document.body.style.setProperty("--bg-color", v));

});

在此總結下CSS使用變量的好處:

減少樣式代碼的重複性

增加樣式代碼的擴充性

提高樣式代碼的靈活性

增多一種CSS與JS的通訊方式

不用深層周遊DOM改變某個樣式

可能有些同學會問,Sass和Less早就實作了變量這個特性,何必再多此一舉呢。可是細想一下,CSS變量對比Sass和Less的變量,又有它的過人之處。

浏覽器原生特性,無需經過任何轉譯就可直接運作

DOM對象一員,極大便利了CSS與JS之間的聯系

認識

本來打算用一半篇幅講述CSS變量的規範和用法,但是網上一搜一大把就感覺沒必要了,貼上阮一峰老師寫的教程《CSS變量教程》。同時筆者也對CSS變量的細節地方進行一個整理,友善大家記憶。

聲明:--變量名

讀取:var(--變量名, 預設值)

類型

普通:隻能用作屬性值不能用作屬性名

字元:與字元串拼接 "Hello, "var(--name)

數值:使用calc()與數值機關連用 var(--width) * 10px

作用域

範圍:在目前元素塊作用域及其子元素塊作用域下有效

優先級别:内聯樣式 > ID選擇器 > 類選擇器 = 屬性選擇器 = 僞類選擇器 > 标簽選擇器 = 僞元素選擇器

接下來使用幾個特别的場景展示CSS變量的魅力。還是那句話,一樣東西有使用的場景,那自然就會有它的價值,那麼用的人也會越來越多。

使用場景

其實CSS變量有一個特别好用的場景,那就是結合List元素集合使用。如果不明白這是什麼,請繼續往下看。

以下所有示範代碼基于vue檔案,但HTML、CSS和JS分開書寫,為了簡化CSS的書寫而使用Sass進行預處理,友善代碼示範

條形加載條

一個條形加載條通常由幾條線條組成,并且每條線條對應一個存在不同時延的相同動畫,通過時間差運作相同的動畫,進而産生加載效果。估計大部分的同學可能會把CSS代碼寫成以下這樣。

.loading {

width: 200px;

height: 200px;

li {

border-radius: 3px;

width: 6px;

height: 30px;

background-color: #f66;

animation: beat 1s ease-in-out infinite;

& + li {

margin-left: 5px;

}

&:nth-child(2) {

animation-delay: 200ms;

&:nth-child(3) {

animation-delay: 400ms;

&:nth-child(4) {

animation-delay: 600ms;

&:nth-child(5) {

animation-delay: 800ms;

&:nth-child(6) {

animation-delay: 1s;

}

分析代碼發現,每個

隻是存在animation-delay不同,而其餘代碼則完全相同,換成其他類似的List元素集合場景,那豈不是有10個

就寫10個:nth-child。

顯然這種方法不靈活也不容易封裝成元件,如果能像JS那樣封裝成一個函數,并根據參數輸出不同的樣式效果,那就更棒了。說到這裡,很明顯就是為了鋪墊CSS變量的開發技巧了。

對于HTML部分的修改,讓每個

擁有一個自己作用域下的CSS變量。對于CSS部分的修改,就需要分析哪些屬性是随着index遞增而發生規律變化的,對規律變化的部分使用CSS變量表達式代替即可。

.strip-loading {

--time: calc((var(--line-index) - 1) * 200ms);

animation: beat 1.5s ease-in-out var(--time) infinite;

代碼中的變量--line-index和--time使每個

擁有一個屬于自己的作用域。例如第2個

,--line-index的值為2,--time的計算值為200ms,換成第3個

後這兩個值又會不同了。

這就是CSS變量的作用範圍所緻(在目前元素塊作用域及其子元素塊作用域下有效),是以在.strip-loading的塊作用域下調用--line-index是無效的。

/* flex屬性無效 */

display: flex;

align-items: center;

flex: var(--line-index);

通過妙用CSS變量,也把CSS代碼從29行縮減到15行,對于那些含有List元素集合越多的場景,效果就更明顯。而且這樣寫也更加美觀更加容易維護,某天說加載效果的時間差不明顯,直接将calc((var(--line-index) - 1) * 200ms)裡的200ms調整成400ms即可。就無需對每個:nth-child(n)進行修改了。

心形加載條

前段時間刷掘金看到陳大魚頭兄的心形加載條,覺得挺漂亮的,很帶感覺。

通過動圖分析,發現每條線條的背景色和動畫時延不一緻,另外動畫運作時的高度也不一緻。細心的你可能還會發現,第1條和第9條的高度一緻,第2條和第8條的高度一緻,依次類推,得到高度變換相同類的公式:對稱index = 總數 + 1 - index。

背景色使用了濾鏡的色相旋轉hue-rotate函數,目的是為了使顔色過渡得更加自然;動畫時延的設定和上面條形加載條的設定一緻。下面就用CSS變量根據看到的動圖實作一番。

.heart-loading {

ul {

display: flex;

justify-content: space-between;

width: 150px;

height: 10px;

--Θ: calc(var(--line-index) / var(--line-count) * .5turn);

--time: calc((var(--line-index) - 1) * 40ms);

border-radius: 5px;

width: 10px;

background-color: #3c9;

filter: hue-rotate(var(--Θ));

animation-duration: 1s;

animation-delay: var(--time);

animation-iteration-count: infinite;

.line-1,

.line-9 {

animation-name: line-move-1;

.line-2,

.line-8 {

animation-name: line-move-2;

.line-3,

.line-7 {

animation-name: line-move-3;

.line-4,

.line-6 {

animation-name: line-move-4;

.line-5 {

animation-name: line-move-5;

一波操作後就有了下面的效果。和陳大魚頭兄的心形加載條對比一下,顔色、波動曲線和跳動頻率有點不一樣,在暖色調的蔓延和腎上腺素的飙升下,這是一種心動的感覺。想起自己曾經寫的一首詩:我見猶憐,愛不釋手,雅俗共賞,君子好逑。

标簽導航欄

上面通過兩個加載條示範了CSS變量在CSS中的運用以及一些妙用技巧,現在通過标簽導航欄示範CSS變量在JS中的運用。

JS中主要有3個操作CSS變量的API,看上去簡單易記,分别如下:

讀取變量:elem.style.getPropertyValue()

設定變量:elem.style.setProperty()

删除變量:elem.style.removeProperty()

先上效果圖,效果中主要是使用CSS變量标記每個Tab的背景色和切換Tab的顯示狀态。

标題{{i + 1}}

内容{{i + 1}}

.tab-navbar {

overflow: hidden;

flex-direction: column-reverse;

border-radius: 10px;

width: 300px;

height: 400px;

nav {

height: 40px;

background-color: #f0f0f0;

line-height: 40px;

text-align: center;

a {

flex: 1;

cursor: pointer;

transition: all 300ms;

&.active {

background-color: #66f;

font-weight: bold;

color: #fff;

}

div {

flex: 1;

ul {

--tab-index: 0;

--tab-width: calc(var(--tab-count) * 100%);

--tab-move: calc(var(--tab-index) / var(--tab-count) * -100%);

display: flex;

flex-wrap: nowrap;

width: var(--tab-width);

height: 100%;

transform: translate3d(var(--tab-move), 0, 0);

li {

justify-content: center;

align-items: center;

background-color: var(--bg-color);

font-weight: bold;

font-size: 20px;

color: #fff;

export default {

data() {

return {

index: 0,

list: ["#f66", "#09f", "#3c9"]

};

},

methods: {

select(i) {

this.index = i;

this.$refs.tabs.style.setProperty("--tab-index", i);

};

上定義--tab-index表示Tab目前的索引,當點選按鈕時重置--tab-index的值,就可實作不操作DOM來移動

的位置顯示指定的Tab。不操作DOM而可移動

是因為定義了--tab-move,通過calc()計算--tab-index與--tab-move的關系,進而操控transform: translate3d()來移動

另外在

上定義--bg-color表示Tab的背景色,也是一種比較簡潔的模闆指派方式,總比寫

要好看。如果多個CSS屬性依賴一個變量指派,那麼使用CSS變量指派到style上就更友善了,那些CSS屬性可在CSS檔案裡進行計算與指派,這樣可幫助JS分擔一些屬性計算工作。

當然,這個标簽導航欄也可通過純CSS實作,有興趣的同學可看看筆者之前一篇文章裡的純CSS标簽導航欄。

懸浮跟蹤按鈕

通過幾個栗子實踐了CSS變量在CSS和JS上的運用,相信大家已經掌握了其用法和技巧。之前在某個網站看過一個比較酷炫的滑鼠懸浮特效,好像也是使用CSS變量實作的。筆者憑着記憶也使用CSS變量實作一番。

其實思路也比較簡單,先對按鈕進行布局和着色,然後使用僞元素标記滑鼠的位置,定義--x和--y表示僞元素在按鈕裡的坐标,通過JS擷取滑鼠在按鈕上的offsetLeft和offsetLeft分别指派給--x和--y,再對僞元素添加徑向漸變的背景色,大功告成,一個酷炫的滑鼠懸浮跟蹤特效就這樣誕生了。

妙用CSS變量,讓你的CSS變得更心動

.track-btn {

display: block;

border-radius: 100px;

width: 400px;

height: 50px;

background-color: #66f;

line-height: 50px;

cursor: pointer;

font-weight: bold;

font-size: 18px;

color: #fff;

span {

position: relative;

&::before {

--size: 0;

position: absolute;

left: var(--x);

top: var(--y);

width: var(--size);

height: var(--size);

background-image: radial-gradient(circle closest-side, #09f, transparent);

content: "";

transform: translate3d(-50%, -50%, 0);

transition: all 200ms ease;

&:hover::before {

--size: 400px;

name: "track-btn",

move(e) {

const x = e.pageX - e.target.offsetLeft;

const y = e.pageY - e.target.offsetTop;

e.target.style.setProperty("--x", `${x}px`);

e.target.style.setProperty("--y", `${y}px`);

其實可結合滑鼠事件來完成更多的酷炫效果,例如動畫關聯、事件響應等操作。沒有做不到,隻有想不到,盡情發揮你的想象力啦。

之前在CodePen上還看到一個挺不錯的栗子,一個懸浮視差按鈕,具體代碼涉及到一些3D變換的知識。看完源碼後,按照其思路自己也實作一番,順便對代碼稍加改良并封裝成Vue元件,存放到本課件示例代碼中。感覺錄制的GIF有點别扭,顯示效果不太好,有興趣的同學可下載下傳本課件示例代碼,自己運作看看效果。

相容

對于現代浏覽器來說,CSS變量的相容性其實還是蠻好的,是以大家可放心使用。畢竟現在都是各大浏覽器廠商快速疊代的時刻,産品對于使用者體驗來說是占了很大比重,是以在條件允許的情況下還是大膽嘗新,不要被一些過去的所謂的規範所限制着。

試問現在還有多少人願意去維護IE6~IE9的相容性,如果一個産品的使用者體驗受限于遠古浏覽器的壓制(可能政務Web應用和金融Web應用除外吧),相信這個産品也不會走得很遠。

我們在完成一個産品的過程中,不僅僅是為了完成工作任務,如果在保證進度的同時能花點心思點綴一下,可能會有意外的收獲。用心寫好每一段代碼,才是享受寫代碼的真谛。

總結

本文通過循序漸進的方式探讨了CSS變量的運用和技巧,對于一個這麼好用的特性,當然是不能放過啦。其實多多思考,就能把CSS變量用在很多場景上。