巧妙的 CSS 變量
在 CSS 中使用變量,是長期以來所有前端夥伴們的急迫訴求。 通過構建工具,我們已經可以在 Sass 和 Less 中愉快地使用變量。 那麼 CSS 變量,又能給我們帶來什麼呢?僅僅是跟着走 Sass/Less 所走過的路嗎? 不,作爲標準的親兒子,CSS 變量有着無可比擬的優越性。
動態性
Sass/Less 中的變量,在項目構建之後,被常量所替代。 即,我們不可能通過客戶端 JS 去訪問,或動態地修改這些變量。它們歸根結底,是靜態的。 而 CSS 變量,是動態的。@media 和 JS 可以動態地修改這些變量,而引用它們的地方,將同步改變。
更好的作用域規則
CSS 變量,又稱爲“自定義屬性”。從作用域的角度看,它不像 Sass/Less 的變量,而像普通的 CSS 屬性。
Sass/Less 變量的作用域就是語法上的,也就是一對{}
之間。
而 CSS 變量,則和一般屬性一樣,通過選擇器,綁定到 DOM 之上,並在 DOM 節點和其字節點中有效。
Sass/Less 變量的作用域取決於你怎麼寫,CSS 變量作用域取決於最終的 DOM 樹。
這有什麼好處呢?別急,先來看一個例子。
組件化思想與自定義屬性
這裏我們給 button
設置尺寸,依據是變量 --button-size
的值,若不存在,則取缺省值爲 1
。
這個規則,將應用於頁面上所有的 <button>
上。
又在 body>main
上設置了 --button-size: 1.5
。規則作用於 <body>
下,直屬的 <main>
上。
容易預見,所有這個 <main>
中的 <button>
的高度爲 1.5rem
,而外部的 <button>
則高度爲 1rem
。
寫 C 的夥伴:不科學!變量怎麼能使用在先,定義在後?怎麼能取到別的作用域下的變量?
讓我們換個角度來理解問題,把 button
部分看作是函數,而將其中的 --button-size
看作參數(形參)。
這個“函數”將在 <button>
被渲染時調用。而此時,body>main
上所賦予的值,將作爲參數(實參)傳入。
這個小例子體現出了封裝,以及組件化的思想。 button 是這樣一個組件,有着內部的樣式,又向外暴露若干參數接口。可在各種場景中復用。 而外界不對這個組件的普通樣式進行入侵,只修改其所暴露的參數。 此時,CSS 變量,就好似組件的自定義樣式屬性。
至此,還不是真正的組件化,我們必須以規範來避免外界的樣式入侵。一旦不小心破壞規則,一切將亂套。 所幸,我們已經有 Web Components。
結合 Web Components
Custom Elements 中,組件裏的樣式表與外界幾乎是隔離的。但 CSS 變量卻可以穿透這個屏障。是十分便利的通信渠道。 這是一個自定義元素內部 CSS 的例子。
此例中,我們使用變量給自定義元素內部的 button 定義樣式。與前面的例子是一樣的。
值得注意的是,我們在 :host
上聲明了 --button-size
,而沒有聲明 --font-size
。
造成的區別就是:任何外層元素上定義的 --font-size
將對自定義元素內的 <button>
產生影響;
而外部要想設置 --button-size
的值,必須直接定義在這個自定義元素上。
兩種方式,各有其適用的場景。
--button-size
的方式,適用於一般情況下組件接受外部參數。參數必須明確地直接傳遞給組件,避免混亂。
而 --font-size
的方式,適用於讀取全局或局部的配置,不可濫用。
與 JS 的交互
以下是 JS 操作樣式的接口,可以操作普通的樣式屬性,以及自定義屬性(CSS 變量)。
即便是普通 CSS 屬性,這也是更好的操作方式。推薦統一使用這套接口操作樣式。
有一種場景是,JS 捕獲用戶事件後,獲取事件參數,例如鼠標的位置;並讀取一些佈局信息, 例如某個 DOM 的寬高;再經過一系列計算後,將幾個計算結果設置到該 DOM 的 style 上。 這樣,JS 就干涉了佈局,與 CSS 強耦合,違背了關注點分離。 由於存在對佈局信息的讀取,會引起額外的重繪。
使用 CSS 變量,則完美地解決了這個痛點。JS 中你只需將鼠標的位置傳遞給 CSS 變量,
而無需注意其它細節。在 CSS 中通過 calc()
完成計算和佈局。
很好地遵循了關注點分離,也避免了額外的重繪。
數據類型
在 CSS 中,基本數據類型有數量,字符串,關鍵字,顏色等。此外,還有序列。 這些類型的數據,都可以作爲 CSS 變量的值。
使用時,可以自由組合,計算。計算時,要注意結果的單位。
而序列的組合,只要把 ,
和 /
等符號,視爲與 1px
等普通值一樣的序列元素,便能理解其行爲了。
結合過渡與動畫
很遺憾,尚無瀏覽器支持 CSS 變量的過渡效果。只能對常規屬性使用過渡效果或關鍵幀。
因此,有許多很棒的想法還不能實現。譬如色相與亮度以不同的速度變化,例如漸變背景的顏色控制等。期待未來的發展吧。