CSS 自定義屬性—使用篇

編程語言 CSS JavaScript HTML 懶貓學編程 2017-05-04

可讀性更高的 CSS 代碼

在 CSS 自定義屬性: 基礎篇後,我們可以開始著手優化代碼了,通過 CSS 變量能夠提高代碼的可讀性,為後續維護打下良好的基礎。

注意:為敘述簡潔,自定義屬性的兼容方案將不再在下文中贅述,但在實際項目中大家別忘了加上,像下面這樣:

CSS 自定義屬性—使用篇

DRY 原則

堅守 DRY 原則,你不僅能夠逃脫不斷重複寫值的噩夢,當調整屬性值要做的搜索、替換和調試等重複的工作都能得以緩解。也就是:DRY 原則能降低代碼維護的成本。

我們來看一個例子,下面這段代碼相當糟糕,多次重複了 gray 這個值:

CSS 自定義屬性—使用篇

如果你希望更改主題色的話,需要調整三個地方的屬性值,還要注意不要錯改了 .caption 的 color 值。

那麼 CSS 變量能派上什麼用場呢?一處定義,處處使用!在引入 --theme-color 之後:

CSS 自定義屬性—使用篇

用 CSS 自定義屬性作為主題色的變量後,一旦要調整,只需要改動一個地方就能全局生效。不止如此,--theme-color 這個變量名已經帶上了語義,之前只是用 gray 的時候,我們並不知道當主題色發生變化的時候,特定元素的字體顏色是否也需要隨之改變。使用該變量後,就沒有了這樣的困擾。

最好也用自定義屬性控制標題的字色 (caption text):

CSS 自定義屬性—使用篇

旅途才剛剛開始,讓我們繼續吧!

是時候放下計算器了

在 CSS 自定義屬性:基礎篇中,我們提到了自定義屬性和 calc() 結合實現運行時的計算。在這個前提下,想想看下面這個網格佈局要如何實現呢:

CSS 自定義屬性—使用篇

CSS 自定義屬性—使用篇

熟悉 CSS 盒模型的你應該很熟悉上面的代碼吧:16px 寬的邊距,.image 間有 16px 寬的間隔。但從 CSS 角度來看,這段代碼還不夠直觀足以代表最終的網格效果,我們真正關心的東西也不能從代碼中凸顯出來。

從設計的角度來看,格子間距和容器邊緣寬度都是 16px,這一點是最重要的。我們的目標是直觀地反饋出設計意圖,直接得到結果對我們來說沒有實現以外的意義。而且分開設置這兩個值也有維護成本。

如果將自定義屬性和 calc() 結合,代碼就會變得更加直觀:

CSS 自定義屬性—使用篇

現在,我們可以直接看到計算過程,如果想要調整數值也很方便。甚至,你還能將變量變成頁面級的,將 --page-grid 的值作為其他元素的基礎值:

CSS 自定義屬性—使用篇

在上面的例子中,我們需要在 calc() 中做一些中間計算,讓最終代碼更清晰。

注意: Safari/WebKit 目前在 calc() 中的計算還有一些問題,這些問題在 Safari 10.1 中有望得到解決。

可讀的變化

到目前,我們都關注在 CSS 自定義屬性的一處定義處處使用,但它的威力不止如此,如果你想在特定的情況下改變變量值,也是可以做到的。

讓我們來看看一個用 flexbox 實現的響應式網格:

CSS 自定義屬性—使用篇

上面這段代碼實現的是一組響應式佈局,但乍看上去,一頭霧水。默認情況下,圖片排成一列,也就是一行只顯示一張圖片;如果屏幕尺寸是600px、1024px…相應的,圖片排列變成了三列或者是六列。和上一段代碼例子中一樣,此處容器邊緣寬度和網格間距都是16px。

calc() 中的計算內容比較複雜,我們需要加上註釋解釋。但如果用上了自定義變量,情況就不同了:

CSS 自定義屬性—使用篇

可以看出,所有的計算都是在一處完成的。在媒體查詢中需要改變的只有自定義屬性的值。現在即使是剛看到這段代碼的人,也能很快讀懂它。而且不再需要不斷使用 calc() 做各種計算了,也規避了因為打錯而造成的問題。

注意:上面某些用法對於 CSS 預處理器來說可能太複雜了,在實際使用中可能不會按照預期生成代碼。

CSS 自定義屬性在存值取值方面有很大作用。接下來我們將探索自定義屬性作為 CSS 和 JavaScript 間橋樑的使用。接下來,讓我們看看 CSS 自定義屬性和 JS 結合能發揮的作用吧!

通過 CSS Class 保證 CSS 和 JavaScript 的獨立性

在大部分情況下,我們都希望 CSS 和 JavaScript 可以解耦。最簡單並利於維護的方式就是使用語義化良好的 CSS class。通過 JS 動態添加或移除 class,改變視覺效果:

CSS 自定義屬性—使用篇

這樣做就不再需要通過 JS 添加行內樣式,它只負責觸發視覺的變化,真正改變視覺的是 CSS。反之,如果需要更改觸發事件但依舊使用同一個視覺變化效果,只用修改 JS 代碼。

注意:建議將通過 JS 控制的 CSS class 和默認的 class 區分開來。比如加上 js- 的前綴(見上段代碼片段)就是個不錯的選擇。

在 CSS 和 JavaScript 中傳值

class 的添加或移除在非黑即白的場景下很合適,但往往情況很複雜,可能還需要動態地傳入一些值。比如,在和用戶輸入有關的場景中,根據用戶的輸入決定某些視覺展現。

假設現在有一個容器元素,我們希望當用戶點擊它的時候可以移動到最後一位。如果在該容器中設置一個輔助性元素,我們可以這樣移動它:

CSS 自定義屬性—使用篇

雖然上面這段代碼能實現我們想要的效果,但 JS 不僅需要直接操作那個輔助性元素(理想情況下,它甚至不應該知道這個元素的存在),還需要通過內聯樣式修改這個元素的 transform 屬性值。

直到現在,這個問題還是沒有完美解決的方式。但有了自定義屬性之後,我們至少可以將這個解決方法抽象化一些了:

CSS 自定義屬性—使用篇

現在又回到了用 CSS 處理視覺表現上了,不再需要通過 JS 更改內聯樣式。事實上,連輔助元素都能用 ::after 偽元素替代:

CSS 自定義屬性—使用篇

提示: 直接通過 JS 修改偽元素(比如 ::after)的樣式不大容易,可以考慮在父元素上使

用自定義屬性作為 JavaScript 和 CSS 之間的橋樑。這是個簡單又容易維護的解決方案!

一個變量,多處使用

邏輯上的變化可能伴隨著大面積視覺表現上的更改,典型的例子就是選擇主題,更換主題時可能引起大部分元素視覺上的變化。

以音樂播放器為例,如果你希望界面顏色隨著當前收聽專輯的更改而變化,從前你需要維護一系列會出現顏色變化的元素以及屬性,需要的時候依次更改:

CSS 自定義屬性—使用篇

HTML 結構如下:

CSS 自定義屬性—使用篇

不管怎麼樣,都要常常更新跟隨主題變化的元素和屬性,所以這個方法會讓後續維護變得艱難。

還有一種解決方式是引入一個新樣式,它將會覆蓋舊樣式。這個方法相對好一些(雖然比較 hacky),但還是避免不了要覆蓋一系列的樣式,這其中依然有著維護成本:

CSS 自定義屬性—使用篇

但通過自定義屬性,問題能得到不小的簡化:只要改變位於 DOM 結構中最高點的元素,接著讓瀏覽器去改變該節點之下的節點:

CSS 自定義屬性—使用篇

JavaScript 根本不需要知道哪些元素哪些屬性會發生變化,也不需要開發者維護受影響的元素列表。使用自定義元素,明顯比前文中的方案都好!

意義

減少對 CSS class 的操作,讓 CSS 自定義屬性幫助你構建出一個 JS 和 CSS 解耦的頁面。

CSS 自定義屬性能讓運行時的任何更改都將侷限在一組明確定義的實體中,這組實體就是為了交互而存在的。這樣,也降低了開發者定位 bug 的難度,還能讓樣式和行為分離。

既然樣式和邏輯獨立於彼此,樣式只有 CSS 來實現,邏輯也只由 JS 來完成,維護也變得更加容易。

相關推薦

推薦中...