原Slides: 4½ Methods for Theming in (S)CSS ; 做者: Harry Robertscss
PM說要實現一個一鍵設置主題的功能,做爲技術,你能想到的實現方式有哪些呢?html
相信你們對網頁的主題樣式功能確定不陌生。對於一些站點,在基礎樣式上,開發者還會爲用戶提供多種主題樣式以供選擇。瀏覽器
下面就是一個主題樣式功能:用戶能夠在右側選擇本身喜歡的主題色,從而獲得一個「個性」的頁面。緩存
還有時候,咱們開發了一個系統用來售賣,採購咱們系統的客戶可能有多個。也許其中一個客戶很喜歡咱們當前的深色色系主題,可是另外一個系統的採購方但願咱們能爲它們定製一套新的樣式。他們但願買來的系統能貼合它們本身的品牌調性,變爲淺色的。這其實也是一種主題樣式的需求。ide
在上面的討論裏,除了「主題」外,咱們又引出了一個概念——個性化。常常,咱們說到主題時,還會有一種說法叫作:個性化主題。這二者在英文中分別有兩個對應的詞: Theming 與 Customisation。工具
當咱們說主題(Theming)與個性化定製(Customisation)的時候,不少時候其實並無區分二者。但實際上,二者仍是有一些微妙的區別的。字體
咱們說的主題(Theming)與個性化定製(Customisation)的時候,仍是有一些微妙的區別的。網站
主要表如今:spa
例如,咱們常見的一些應用會提供夜間主題、閱讀模式,這些也算是主題(Theming)的範疇。code
特色表如今:
能夠看到,「個性化」其實更強調了用戶對系統的的影響力。
不少時候,咱們談到「主題」與「個性化定製」時,也許並無一個明確的邊界。從上面的描述也能夠看出,二者彷佛是處於天平的兩端,區別主要在於開發者對規則的控制力度以及所能實現的差別化的粒度。
而咱們更多的是在兩點之間找到一個平衡點。
咱們已經對主題樣式有了初步的瞭解,若是你也在產品中遇到了主題樣式的相關需求,不妨先看看如下幾點建議:
Overriding default style with additional CSS.
這應該是實現主題功能的一種最經常使用的手段了。首先,咱們的站點會有一個最初的基礎樣式(或者叫默認樣式);而後經過添加一些後續的額外的CSS來覆蓋與從新定義部分樣式。
首先,咱們引入基礎的樣式 components.*
文件
@import "components.tabs";
@import "components.buttons"
複製代碼
其中 components.tabs
文件內容以下
.tab {
margin: 0;
padding: 0;
background-color: gray;
}
複製代碼
而後,假設咱們的某個主題的樣式文件存放於 theme.*
文件:
對應於 components.tabs
,theme.tabs
文件內容以下
.tab {
background-color: red;
}
複製代碼
所以,咱們只須要引入主題樣式文件便可
@import "components.tabs";
@import "components.buttons"
@import "theme.tabs";
複製代碼
這樣當前的樣式就變爲了
.tab {
margin: 0;
padding: 0;
/* background-color: gray; */
background-color: red;
}
複製代碼
Styling a UI based on a state or condition.
該方式能夠實現基於條件選擇不一樣的主題皮膚,並容許用戶在客戶端隨時切換主題。很是適合須要客戶端樣式切換功能,或者須要對站點某一部分(區域)進行獨立樣式設置的場景。
仍是相似上一節中 Tab 的這個例子,咱們能夠將 Tab 部分的 (S)CSS 改成以下形式:
.tab {
background-color: gray;
.t-red & {
background-color: red;
}
.t-blue & {
background-color: blue;
}
}
複製代碼
這裏咱們把.t-red
與.t-blue
稱爲 Tab 元素的上下文環境(context)。Tab 元素會根據 context 的不一樣展現出不一樣的樣式。
最後咱們給body
元素加上這個開關
<body class="t-red">
<ul class="tabs">...</ul>
</body>
複製代碼
此時 Tab 的顏色爲紅色。
當咱們將t-red
改成t-blue
時,Tab 就變爲了藍色主題。
進一步的,咱們能夠建立一些 (S)CSS 的 util class(工具類)來專門控制一些 CSS 屬性,幫助咱們更好地控制主題。例如咱們使用以下的.u-color-current
類來控制不一樣主題下的字體顏色
.u-color-current {
.t-red & {
color: red;
}
.t-blue & {
color: blue;
}
}
複製代碼
這樣,當咱們在不一樣主題上下文環境下使用.u-color-current
時,就能夠控制元素展現出不一樣主題的字體顏色
<body class="t-red">
<h1 class="page-title u-color-current">...</h1>
</body>
複製代碼
上面這段代碼會控制<h1>
元素字體顏色爲紅色主題時的顏色。
Invoking a theme based on settings.
這種方式實際上是在開發側來實現主題樣式的區分與切換的。基於不一樣的配置,配合一些開發的自動化工具,咱們能夠在開發時期根據配置文件,編譯生成不一樣主題的 CSS 文件。
它通常會結合使用一些 CSS 預處理器,能夠對不一樣的 UI 元素進行主題分離,而且向客戶端直接提供主題樣式下最終的 CSS。
咱們仍是以 Sass 爲例:
首先會有一份 Sass 的配置文件,例如settings.config.scss
,在這份配置中定義當前的主題值以及一些其餘變量
$theme: red;
複製代碼
而後對於一個 Tab 組件,咱們這麼來寫它的 Sass 文件
.tab {
margin: 0;
padding: 0;
@if ($theme == red) {
background-color: red;
} @else {
background-color: gray;
}
}
複製代碼
這時,咱們在其以前引入相應的配置文件後
@import "settings.config";
@import "components.tabs";
複製代碼
Tab 組件就會呈現出紅色主題。
固然,咱們也能夠把咱們的settings.config.scss
作的更健壯與易擴展一些
$config: (
theme: red,
env: dev,
)
// 從$config中獲取相應的配置變量
@function config($key) {
@return map-get($config, $key);
}
複製代碼
與以前相比,這時候使用起來只須要進行一些小的修改,將直接使用theme
變量改成調用config
方法
.tab {
margin: 0;
padding: 0;
@if (config(theme) == red) {
background-color: red;
} @else {
background-color: gray;
}
}
複製代碼
settings.config.scss
文件)Holding entire themes in a palette file.
這種方式有些相似於咱們繪圖時,預設了一個調色板(palette),而後使用的顏色都從其中取出同樣。
在實現主題功能時,咱們也會有一個相似的「調色板」,其中定義了主題所須要的各類屬性值,以後再將這些信息注入到項目中。
當你常常須要爲客戶端提供徹底的定製化主題,而且常常但願更新或添加主題時,這種模式會是一個不錯的選擇。
在方式三中,咱們在一個獨立的配置文件中設置了一些「環境」變量,來標示當前所處的主題。而在方式四中,咱們會更進一步,抽取出一個專門的 palette 文件,用於存放不一樣主題的變量信息。
例如,如今咱們有一個settings.palette.red.scss
文件
$color: red;
$color-tabs-background: $color-red;
複製代碼
而後咱們的components.tabs.scss
文件內容以下
.tabs {
margin: 0;
padding: 0;
backgroung-color: $color-tabs-background;
}
複製代碼
這時候,咱們只須要引入這兩個文件便可
@import "settings.palette.red";
@import "components.tabs";
複製代碼
能夠看到,components.tabs.scss
中並無關於主題的邏輯判斷,咱們只須要專一於編輯樣式,剩下就是選擇所需的主題調色板(palette)便可。
Letting users style their own UIs.
這種模式通常會提供一個個性化配置與管理界面,讓用戶能本身定義頁面的展現樣式。
「用戶定製化」在社交媒體產品、SaaS 平臺或者是 Brandable Software 中最爲常見。
要實現定製化,能夠結合方式二中提到的 util class。
首先,頁面中支持自定義的元素會被預先添加 util class,例如 Tab 元素中的u-user-color-background
<ul class="tabs u-user-color-background">...</ul>
複製代碼
此時,u-user-color-background
還並未定義任何樣式。而當用戶輸入了一個背景色時,咱們會建立一個<style>
標籤,並將 hex 值注入其中
<style id="my-custom"> .u-user-color-background { background-color: #00ffff; } </style>
複製代碼
這時用戶就獲得了一個紅色的 Tab。
Twitter 就是使用這種方式來實現用戶定製化的界面樣式的:
最後來聊聊方案的選擇。
在第二部分咱們已經瞭解了五種實現方式(或者說4½種方法,由於第五種其實更偏個性化定製一些),那麼面對產品需求,咱們應該如何選擇呢?
這裏有一個不是很是嚴謹的方式能夠參考。你能夠經過嘗試問本身下面這幾個問題來作出決定:
是你仍是用戶誰來肯定樣式? 用戶:選擇【方式五】User Customisation
主題是否會在客戶端中被切換? 是:選擇【方式二】Stateful Theming 或【方式五】User Customisation
是否有主題能讓用戶切換? 是:選擇【方式二】Stateful Theming
你是但願網站的某些部分須要有不一樣麼? 是:選擇【方式二】Stateful Theming
是否有預設的主題讓客戶端來選擇? 是:選擇【方式三】Config Theming
是不是相似「貼牌」這類場景? 是:選擇【方式一】Theme Layer 或【方式四】Theme Palettes