如何使用 CSS 自定義屬性配置應用程序配色方案

已發表: 2022-03-10
快速總結 ↬在本文中,Artur Basak 介紹了一種現代方法來設置響應應用程序顏色的 CSS 自定義屬性。 將顏色分為三個級別的想法非常有用:調色板(或方案)、功能顏色(或主題)和組件顏色(局部範圍)。

變量是幫助組織項目顏色的基本工具。 長期以來,前端工程師使用預處理器變量來配置項目的顏色。 但現在,許多開發人員更喜歡組織顏色變量的現代原生機制:CSS 自定義屬性。 與預處理器變量相比,它們最重要的優勢是它們實時工作,而不是在項目的編譯階段,並且支持級聯模型,允許您即時使用繼承和重新定義值。

當您嘗試組織應用程序配色方案時,您始終可以將所有與顏色相關的自定義屬性放在根部分,命名它們,並在所有需要的地方使用它。

請參閱 Artur Basak 的 Pen [自定義顏色屬性](https://codepen.io/smashingmag/pen/RwaNqxW)。

請參閱 Artur Basak 的顏色筆自定義屬性。

這是一個選項,但它是否可以幫助您解決應用程序主題化、白標、品牌更新或組織明暗模式的問題? 如果您需要調整配色方案以增加對比度怎麼辦? 使用當前方法,您將不得不更新變量中的每個值。

在本文中,我想就如何使用自定義屬性來拆分顏色變量提出一種更靈活、更可靠的方法,它可以解決許多此類問題。

跳躍後更多! 繼續往下看↓

設置調色板

任何網站的著色都始於配色方案的設置。 這種方案基於色輪。 通常,只有少數原色構成調色板的基礎,其餘的都是派生色——色調和中間色調。 大多數情況下,調色板是靜態的,並且在 Web 應用程序運行時不會更改。

根據色彩理論,配色方案只有幾種選擇:

  • 單色方案(一種原色)
  • 互補方案(兩種原色)
  • 三色方案(三基色)
  • 四色方案(四基色)
  • 相鄰圖案(二或三基色)

對於我的示例,我將使用 Paletton 服務生成三元組配色方案:

具有已建立的三色方案的色輪:綠色、藍色和紅色的變化。
調色板服務:三元配色方案。 (大預覽)

我現在有三種主要顏色。 在這些基礎上,我將計算色調和中間色調(HSL 格式結合calc函數是一個非常有用的工具)。 通過更改亮度值,我可以為調色板生成幾種額外的顏色。

請參閱 Artur Basak 的 Pen [HSL Palette](https://codepen.io/smashingmag/pen/OJNPaQW)。

請參閱 Artur Basak 的 Pen HSL Palette。

現在,如果修改了調色板,則只需要更改原色的值。 其餘的將自動重新計算。

如果您更喜歡 HEX 或 RGB 格式,那沒關係; 可以在編譯項目的階段使用預處理器的相應功能(例如,使用 SCSS 和color-adjust功能)形成調色板。 正如我之前提到的,這一層大部分是靜態的。 在正在運行的應用程序中更改調色板的情況極為罕見。 這就是為什麼我們可以使用預處理器來計算它。

注意我建議同時為每種顏色生成 HEX 文字和 RGB。 這將允許在未來使用 Alpha 通道。

請參閱 Artur Basak 的 Pen [SCSS Palette](https://codepen.io/smashingmag/pen/oNxgQqv)。

請參閱 Artur Basak 的 Pen SCSS Palette。

調色板級別是唯一將顏色直接編碼在變量名稱中的級別,即我們可以通過讀取名稱來唯一地識別顏色。

定義主題或功能顏色

一旦調色板完成,下一步就是功能顏色的級別。 在這個層面上,顏色的價值並不像它的用途、它執行的功能以及它究竟著色什麼那麼重要。 例如,主要或應用品牌顏色、邊框顏色、深色背景上的文本顏色、淺色背景上的文本顏色、按鈕背景顏色、鏈接顏色、懸停鏈接顏色、提示文本顏色等.

對於幾乎任何網站或應用程序來說,這些都是極其常見的事情。 可以說,這些顏色負責應用程序的某個顏色主題。 此外,這些變量的值嚴格取自調色板。 因此,我們可以通過簡單地使用不同的調色板來輕鬆更改應用程序主題。

下面,我創建了三個典型的 UI 控件:按鈕、鏈接和輸入字段。 它們使用包含我之前在上面生成的調色板中的值的函數變量進行著色。 負責應用程序主題(條件品牌)的主要功能變量是原色變量。

使用頂部的三個按鈕,您可以切換主題(更改控件的品牌顏色)。 通過使用適當的 CSSOM API (setProperty) 進行更改。

請參閱 Artur Basak 的鋼筆 [功能顏色](https://codepen.io/smashingmag/pen/poyvQLL)。

請參閱 Artur Basak 的鋼筆功能顏色。

這種方法不僅對主題化很方便,而且對配置單個網頁也很方便。 例如,在 zubry.by 網站上,我使用了一個通用樣式表和一個函數變量--page-color來為所有頁面的徽標、標題、控件和文本選擇著色。 並且在每個頁面的自己的樣式中,我只是重新定義了這個變量來將頁面設置為它自己的原色。

ZUBRY.BY網站的3個網頁:郵票頁、明信片頁和卡片頁。
ZUBRY.BY 網站,其中每個頁面都有單獨的原色。 (大預覽)

使用組件顏色

大型 Web 項目總是包含分解; 我們將所有內容拆分為小組件,並在許多地方重複使用它們。 每個組件通常都有自己的樣式,這意味著我們使用什麼來分解 BEM 或 CSS 模塊或其他方法都無關緊要; 重要的是,每段這樣的代碼都可以稱為本地範圍並重用。

一般來說,我在兩種情況下看到在組件級別使用顏色變量的意義。

第一種是當根據應用風格指南重複使用不同設置的組件時,例如用於不同需求的按鈕,如主要(品牌)按鈕、次要按鈕、第三級等。

Tispr 應用程序的不同按鈕樣式。
Tispr 應用程序樣式指南。 鈕扣。 (大預覽)

第二種是當組件具有多種不同顏色的狀態時,例如按鈕懸停、活動和焦點狀態; 輸入或選擇字段的正常和無效狀態,等等。

組件變量可能派上用場的更罕見的情況是“白標”的功能。 “白標”是一項服務功能,允許用戶自定義或標記用戶界面的某些部分,以改善與客戶交互的體驗。 例如,用戶通過服務或電子郵件模板與其客戶共享的電子文檔。 在這種情況下,組件級別的變量將有助於將某些組件與應用程序的其餘顏色主題分開配置。

在下面的示例中,我現在添加了用於自定義主(品牌)按鈕顏色的控件。 使用組件級別的顏色變量,我們可以彼此分開配置 UI 控件。

請參閱 Artur Basak 的鋼筆 [組件顏色](https://codepen.io/smashingmag/pen/LYNEXdw)。

請參閱 Artur Basak 的鋼筆組件顏色。

如何確定變量的級別?

我遇到了一個問題,即如何理解可以在根(主題或功能級別)中放置什麼,以及在組件級別留下什麼。 這是一個很好的問題,如果沒有看到您正在處理的情況,很難回答。

不幸的是,與編程相同的方法不適用於顏色和样式,如果我們看到三段相同的代碼,那麼我們需要對其進行重構。

顏色可以從一個組件到另一個組件重複,但這並不意味著它是一個規則。 這些組件之間不能有任何關係。 例如,輸入字段的邊框和主按鈕的背景。 是的,在我上面的例子中就是這種情況,但讓我們看看下面的例子:

請參閱 Artur Basak 的 Pen [Color Split: Only Palette](https://codepen.io/smashingmag/pen/YzqPRLX)。

請參閱 Artur Basak 的 Pen Color Split: Only Palette。

深灰色重複——這是輸入字段的邊框、關閉圖標的填充顏色和輔助按鈕的背景。 但是這些組件之間沒有任何联系。 如果輸入字段的邊框顏色發生變化,那麼我們不會更改輔助按鈕的背景。 對於這種情況,我們必須只保留調色板中的變量。

UI 控件:按鈕、鏈接、標題和常規文本、輸入字段
應用程序樣式指南示例。 (大預覽)

綠色呢? 我們可以明確將其定義為主色或品牌色,最有可能的是,如果主按鈕的顏色發生變化,那麼第一級的鏈接和標題的顏色也會發生變化。

紅色呢? 輸入字段的無效狀態、錯誤消息和破壞性按鈕在整個應用程序級別將具有相同的顏色。 這是一種模式。 現在我可以在根部分定義幾個常用的函數變量:

請參閱 Artur Basak 的 Pen [Color Split: Functional Level](https://codepen.io/smashingmag/pen/MWyYzGX)。

請參閱 Artur Basak 的鋼筆顏色拆分:功能級別。

關於組件顏色的級別,我們可以輕鬆識別可以使用自定義屬性進行自定義的組件。

按鈕以不同的設置重複,不同用例的背景顏色和文本發生變化——主要、次要、第三、破壞性或負面案例。

輸入字段有兩種狀態——不正確和正常,其中背景和邊框顏色不同。 因此,讓我們將這些設置放入相應組件級別的顏色變量中。

對於其餘的組件,沒有必要定義局部顏色變量,這將是多餘的。

請參閱 Artur Basak 的 Pen [Color Split: Component Level](https://codepen.io/smashingmag/pen/BaKyGVR)。

請參閱 Artur Basak 的鋼筆顏色拆分:組件級別。

您需要深入研究項目的模式語言,這可能是由設計團隊和 UX 開發的。 工程師必須充分理解視覺語言的整個概念,然後我們才能確定什麼是通用的,應該存在於功能層面,什麼應該保持在本地可見範圍內。

但一切都沒有那麼複雜,有明顯的東西。 頁面的一般背景、正文的背景和顏色,在大多數情況下,這就是設置應用程序主題的內容。 收集負責配置特定模式(如暗模式或亮模式)的此類內容非常方便。

為什麼不把所有東西都放在根部分?

我有過這樣的經歷。 在 Lition 項目中,我和團隊面臨這樣一個事實,即我們需要支持 IE11 的 Web 應用程序,而不是網站和登陸。 項目之間使用了一個通用的 UI Kit,我們決定將所有變量放在根目錄中,這將允許我們在任何級別重新定義它們。

對於 Web 應用程序和 IE11 案例,同樣採用這種方法,我們只需通過以下後處理器插件傳遞代碼,並將這些變量轉換為項目中所有 UI 組件的文字。 僅當所有變量都在根部分中定義時,此技巧才有可能,因為後處理器無法理解級聯模型的細節。

帶有打開的瀏覽器開發工具的 Lition 網站主頁
Lition SSR 網站。 根部分中的所有變量。 (大預覽)

現在我明白這不是正確的方法。 首先,如果您將組件顏色放入根部分,那麼您就打破了關注點分離原則。 因此,您最終可能會在樣式表中出現多餘的 CSS。 例如,您有一個組件文件夾,其中每個組件都有自己的樣式。 您還有一個通用樣式表,您可以在其中描述根部分中的顏色變量。 您決定移除按鈕組件; 在這種情況下,您必須記住還要從通用樣式文件中刪除與按鈕關聯的變量。

其次,就性能而言,這不是最佳解決方案。 是的,顏色變化只會導致重新繪製的過程,而不是回流/佈局,這本身並不太昂貴,但是當您在最高級別進行一些更改時,您將使用更多的資源來檢查整個樹而不是這些變化是在一個小的局部區域。 我建議閱讀 Lisi Linhart 的 CSS 變量性能基準以了解更多詳細信息。

在我當前的項目 Tispr 中,我和團隊使用 split 並且不會將所有內容都轉儲到根目錄中,在較高級別上只有調色板和功能顏色。 還有,我們也不怕IE11,因為這個問題是通過對應的polyfill解決的。 只需安裝 npm 模塊 ie11-custom-properties 並將庫導入您的應用程序 JS 包:

 // Use ES6 syntax import "ie11-custom-properties"; // or CommonJS require('ie11-custom-properties');

或者通過腳本標籤添加模塊:

 <script async src="./node_modules/ie11-custom-properties/ie11CustomProperties.js">

此外,您可以通過 CDN 添加不帶 npm 的庫。 這個 polyfill 的工作基於 IE11 對自定義屬性的支持最少的事實,其中可以基於級聯定義和讀取屬性。 這對於以雙破折號開頭的屬性是不可能的,但可能是單破折號(類似於供應商前綴的機制)。 您可以在存儲庫文檔中閱讀有關此內容的更多信息,並了解一些限制。 其他瀏覽器將忽略此 polyfill。

下面是 Tispr Web 應用程序的調色板以及電子文檔(例如用戶合同、發票或提案)的“白標”功能控件。

具有以下列的網格:顏色、顏色名稱、顏色 HEX、顏色 RGB。
Tispr Styleguide:調色板。 (大預覽)
自定義顏色選擇器 UI 組件
Tispr Styleguide:用於白標功能的品牌選擇器。 (大預覽)

為什麼不在 JavaScript 端存儲顏色變量?

另一個合理的問題:為什麼不在 JavaScript 代碼中存儲調色板和函數變量? 這也可以通過內聯樣式動態更改和稍後重新定義顏色。 這可能是一種選擇,但很可能這種方法不太理想,因為您需要訪問某些元素並更改它們的顏色屬性。 使用 CSS 變量,您只會更改一個屬性,即變量值。

在 JavaScript 中,沒有用於處理顏色的本機函數或 API。 在 CSS 顏色模塊 5 中,將有很多機會生成派生顏色或以某種方式計算它們。 從未來的角度來看,CSS 自定義屬性比 JS 變量更豐富、更靈活。 此外,使用 JS 變量,將不可能在級聯中使用繼承,這是主要缺點。

結論

將顏色分為三個級別(調色板、功能和組件)可以幫​​助您在處理項目時更好地適應變化和新要求。 我相信 CSS 自定義屬性是組織顏色拆分的正確工具——無論您使用什麼樣式進行樣式設置:純 CSS、預處理器或 CSS-in-JS 方法。

我是通過自己的經驗得出這種方法的,但我並不孤單。 Sara Soueidan 在她的文章中描述了一種類似的方法,她將變量分為全局和組件級別。

我還想建議閱讀 Lea Verou 的文章,其中她描述了應用 CSS 變量的可能情況(不僅在顏色方面)。