使用 Sass 開發網頁樣式佈景主題應用
網站除了主要的內容呈現外,透過底圖、配色或字型營造出不一樣的風格。讓網站具有更豐富的變化,可以帶給使用者不同的感受。今天要分享近期使用 Sass 在專案開發切換佈景主題的實際應用。使用 Sass 的語法,將佈景樣式設定值透過變數(Variables)方式設定,做為一個設定檔,再加上 @mixin 與 @function 可自動依照設定產生對應的樣式,方便後續增加佈景主題與樣式維護。
說明
範例 html 內容如下,最外層有一個 #app-root 放置所有 DOM 元素。
<div id="app-root">
<div class="card">
<div class="card__header">Card Header</div>
<div class="card__body">...</div>
<div class="card__footer">Card Footer</div>
</div>
</div>
透過 #app-root 容器上增加佈景樣式的 class name 來套用不同佈景樣式,只要配合需要修改容器上的 class name 就可以做到不同佈景樣式切換之效果。無論搭配那一種前端框架(React, Angular, Vue)或是傳統網頁都可以輕易套用。
<div id="app-root" class="theme-light">
...
</div>
<div id="app-root" class="theme-dark">
...
</div>
撰寫樣式
樣式的部份使用 BEM 的命名規則搭配 Sass 的 Nesting 進行開發。
.card {
width: 400px;
border-radius: 10px;
overflow: hidden;
&__header {
height: 50px;
background-color: black;
color: white;
line-height: 50px;
vertical-align: middle;
text-align: center;
}
&__body {
background-color: #eee;
padding: 20px;
}
&__footer {
height: 30px;
background-color: #444;
color: white;
line-height: 30px;
vertical-align: middle;
text-align: right;
padding: 0 20px;
font-size: small;
}
}
定義 themes (需要在使用前被載入)
依據設計稿或已完成的樣式去定義整個網站要用到的變數與設定值,並且將所有佈景的設定放置於 $themes 這個變數內。此範例規劃是 card__header 使用 primary 的設定,card__footer 使用 secondary 的設定。
$themes: (
light: (
primary-color: #ccc,
primary-contrast-color: #000,
secondary-color: #ddd,
secondary-contrast-color: #000
),
dark: (
primary-color: #000,
primary-contrast-color: #fff,
secondary-color: #444,
secondary-contrast-color: #fff
)
);
加入 @mixin 與 @function (需要在使用前被載入)
增加 @mixin themify 處理不同佈景所需要產生的樣式設定。
@mixin themify($themes: $themes) {
// 執行迴圈處理不同佈景所需要產生的樣式
@each $theme, $map in $themes {
// 產生 selector
.theme-#{$theme} & {
// 設定全域 $theme-map 變數預設值
$theme-map: () !global;
// 取出目前對應佈景的所有設定值並放入全域的 $theme-map 變數內
@each $key, $submap in $map {
$value: map-get(map-get($themes, $theme), '#{$key}');
$theme-map: map-merge($theme-map, ($key: $value)) !global;
}
// 輸出所有使用這個 mixin 的所有設定,會搭配 @function themed 使用可取得對應設定值
@content;
// 佈景樣式產生完畢清空全域變數 $theme-map
$theme-map: null !global;
}
}
}
增加 @function themed 從定義好的變數中依據指定的 key 值取出設定值來使用。
@function themed($key) {
// 依據傳入的 key 值,由變數 $theme-map 取得對應的設定值並回傳
@return map-get($theme-map, $key);
}
調整樣式套用佈景設定
將需要套用佈景的樣式透過 @include themify 將樣式框起來,並且使用 themed 指定 key 值做設定。
@include themify($themes) {
background-color: themed("primary-color");
color: themed("primary-contrast-color");
}
將 card__header 與 card__footer 中的背景色與文字顏色做調整,調整後的完整程式碼如下。
.card {
width: 400px;
border-radius: 10px;
overflow: hidden;
&__header {
height: 50px;
@include themify($themes) {
background-color: themed("primary-color");
color: themed("primary-contrast-color");
}
background-color: #eee;
line-height: 50px;
vertical-align: middle;
text-align: center;
}
&__body {
background-color: #eee;
padding: 20px;
}
&__footer {
height: 30px;
@include themify($themes) {
background-color: themed("secondary-color");
color: themed("secondary-contrast-color");
}
background-color: #eee;
line-height: 30px;
vertical-align: middle;
text-align: right;
padding: 0 20px;
font-size: small;
}
}
轉譯後的 CSS
可以觀察一下產出後的結果跟你在撰寫 Sass 時想像的是否相同,確保自已的理解是正確的。
.card {
width: 400px;
border-radius: 10px;
overflow: hidden;
}
.card__header {
height: 50px;
background-color: #eee;
line-height: 50px;
vertical-align: middle;
text-align: center;
}
.theme-light .card__header {
background-color: #ccc;
color: #000;
}
.theme-dark .card__header {
background-color: #000;
color: #fff;
}
.card__body {
background-color: #eee;
padding: 20px;
}
.card__footer {
height: 30px;
background-color: #eee;
line-height: 30px;
vertical-align: middle;
text-align: right;
padding: 0 20px;
font-size: small;
}
.theme-light .card__footer {
background-color: #ddd;
color: #000;
}
.theme-dark .card__footer {
background-color: #444;
color: #fff;
}
以上就是整個撰寫的過程,最重要的部份應該就是那些設定要共用要抽出來成為變數。當然這跟專案的需求都有很大的關係。但實作的方法大概就是如此。至於過程中產出的 @mixin 與 @function 都是以後可以重覆使用的,可自行整理到自已的 Sass 函式庫以後開發樣式直接載入即可使用。