0%

Sass/SCSS 入門:變數、巢狀、混入、繼承

其實過去在 Lidemy 課程中,也有提過 CSS 預處理器的觀念:[week 13] 前端工具之二 - CSS 預處理器、Babel,因為工作上需要使用,發現自己對語法還是不太熟悉,於是整理了這篇筆記。瞭解這套工具的由來,基本語法的使用,以及如何幫助我們解決前端開發可能遇到的問題。

What is CSS 預處理器?

我們所熟知的 CSS,是用來撰寫網頁樣式的語言,但隨著網頁開發複雜度提高,尤其是大型專案,在開發時也面臨許多問題:

  • 全域樣式會互相干擾,不易進行 debug,可維護性差
  • 重複撰寫相同樣式,程式碼不易閱讀

為了解決這些問題,CSS 預處理器(CSS Preprocessor)就誕生了!透過將程式模組化的概念,新增了變數、巢狀結構、混入、繼承等寫法,作為 CSS 語法的擴充,用以改善程式碼的結構與可維護性。

現今較為主流的 CSS 預處理器有下列三種,均賦予 CSS 動態語言的特性:

  • Sass/SCSS:最廣為開發者使用
  • Less:原先是基於 Ruby 開發,後來改用 Node.js 為基底實作
  • Stylus:基於 Node.js 開發

而本篇所探討的 Sass/SCSS,主要包含兩種寫法,分別是:

  • 舊版的 SASS
    • 縮排語法,副檔名 .sass
    • 使用縮排方式編輯巢狀關係
.nav 
  background: #eee
  li 
    display: inline-block
  • 新版的 SCSS
    • 塊語法,副檔名 .scss
    • 使用大括號區分選擇器,使用分號區分屬性,較貼近原生 CSS
.nav {
  background: #eee;
  li {
    display: inline-block;
  }
}

將上述範例程式碼,經編譯過的 CSS 寫法如下:

.nav {
  background: #eee;
}
.nav li {
  display: inline-block;
}

需注意不管使用哪種 CSS 預處理器,程式碼都必須先編譯(compiled)成 CSS 的形式,才能讓瀏覽器解讀並呈現出畫面。

Sass/SCSS 基本語法

詳細教程可參考 Sass 官網

Sass/SCSS 提供的功能主要如下:

  • 參數與結構化 CSS
    • Nesting:巢狀語法
    • Variables:變數設定
  • 模組化 CSS
    • Import 引入檔案,用來分別進行管理
    • Extend 繼承,處理共同樣式
    • Mixin 混入,打包常用功能,替換局部變數
    • Functions 函式
  • 自動化 CSS
    • Condition 條件判斷
    • Loop 跑迴圈:例如使用 @each 搭配 array、@each 搭配 map、for 迴圈

變數 Variables

使用說明:以錢字號 $ 來宣告變數,通常會寫在程式碼最上方,只要有引用該變數的地方,均可統一修改管理,常用於:按鈕顏色、字型字體大小等。

  • 編譯前 SCSS
$font-stack:  Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}
  • 編譯後 CSS
body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

巢狀結構 Nesting

使用說明:需注意縮排寫法,可使用 & 符號來引用父選擇器,常用於 CSS 元件狀態 :hover:focus:before:after 等。

  • 編譯前 SCSS
nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
    &:hover {
      color: red;
    }
  }
}
  • 編譯後 CSS
nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}
nav li {
  display: inline-block;
}
nav a {
  display: block;
  padding: 6px 12px;
  text-decoration: none;
}
nav a:hover {
  color: red;
}

混入 Mixins

使用說明:將經常被重複使用的程式碼獨立撰寫,以 @mixin 語法包裝起來,需要時透過 @include 引用,即可根據不同參數來設定相似的樣式,常用於 width、height、flex-center 等。

  • 編譯前 SCSS:@mixin 可傳入參數
// 經常重複使用的樣式
@mixin transform($property) {
  -webkit-transform: $property;
  -ms-transform: $property;
  transform: $property;
}

// 需要套用樣式的程式碼
.box { 
  @include transform(rotate(30deg));
}
.avatar { 
  @include transform(rotate(90deg));
}
  • 編譯後 CSS:需注意可能出現大量重複的程式碼
.box {
  -webkit-transform: rotate(30deg);
  -ms-transform: rotate(30deg);
  transform: rotate(30deg);
}
.avatar {
  -webkit-transform: rotate(90deg);
  -ms-transform: rotate(90deg);
  transform: rotate(90deg);
}

繼承 Extent/Inderitance

使用說明:當許多選擇器具有相同樣式時,可透過% 佔位符號宣告,將所有相同樣式內容合併,在以 @extend 來引入使用。

  • 編譯前 SCSS:需注意有被 @extend 的 class 才會被編譯成 CSS 程式碼,並且整合到共用樣式
/* This CSS will print because %message-shared is extended. */
%message-shared {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}

// This CSS won't print because %equal-heights is never extended.
%equal-heights {
  display: flex;
  flex-wrap: wrap;
}

.message {
  @extend %message-shared;
}

.success {
  @extend %message-shared;
  border-color: green;
}

.error {
  @extend %message-shared;
  border-color: red;
}

.warning {
  @extend %message-shared;
  border-color: yellow;
}
  • 編譯後 CSS:使用 %message-shared 佔位符號進行宣告的 class,並不會產生實體對象
    /* This CSS will print because %message-shared is extended. */
    .message, .success, .error, .warning {
      border: 1px solid #ccc;
      padding: 10px;
      color: #333;
    }
    
    .success {
      border-color: green;
    }
    
    .error {
      border-color: red;
    }
    
    .warning {
      border-color: yellow;
    }

比較:@mixin@extend 使用時機

使用 @mixin 的好處,是減少重複撰寫樣式的時間,卻也可能造成編譯後的 CSS 樣式大量重複,使檔案異常肥大。

這時可以改用有類似效果的 @extend,同樣能解決重用問題,搭配 placeholder 佔位選擇器,將目標對象進行合併而非載入。

@mixin@extend 兩者的使用時機與差異,可從下列兩點來思考:

  • 是否需傳遞參數
  • 是否需考慮編譯後 CSS 大小

模組 Modules

使用說明:透過 @import@use 語法,可將 SCSS 以模組化的形式,從其他 SCSS 檔案引入需要的樣式,需注意已存在的模組尚未全面支援 @use

  • 編譯前 SCSS:要作為模組載入的 SCSS 檔案,名稱必須帶有底線,例如 _base.scss
// ./_base.scss
$font-stack:    Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

使用 @import:會全部導入樣式,有可能產生命名衝突的狀況:

// styles.scss
@import 'base';

使用@use:代表「參照」,只選擇需要的部分使用,並戴上模組名稱來呼叫,降低衝突的可能性:

// styles.scss
@use 'base';

.inverse {
  background-color: base.$primary-color;
  color: white;
}
  • 編譯後 CSS
body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

.inverse {
  background-color: #333;
  color: white;
}

參考資料:

  • Sass/SCSS 基本語法介紹,搞懂CSS 預處理器
  • SASS教學 +SCSS:CSS 再進化,掌握語法攻略
  • SASS/SCSS 簡介
  • Sass / SCSS 預處理器 - @entend 繼承樣式與 Placeholder 佔位符選擇器