Sass Theme

使用 Sass 開發網頁樣式佈景主題應用

廖汶彬 2019/12/11 18:57:19
2252

網站除了主要的內容呈現外,透過底圖、配色或字型營造出不一樣的風格。讓網站具有更豐富的變化,可以帶給使用者不同的感受。今天要分享近期使用 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 函式庫以後開發樣式直接載入即可使用。

廖汶彬