CSS preprocessor 與 Sass/SCSS 基本語法介紹
隨著網頁開發越發複雜,CSS 的可維護性也越顯重要,但在 CSS 語法仍然受限的狀況下,發展出了 CSS Preprocessor(CSS 預處理器)來擴展更多有彈性的寫法。
本篇文章將介紹關於 CSS 預處理器的幾個要點:
- CSS 預處理器的由來
- 什麼是 CSS 預處理器?
- 為什麼要用 CSS 預處理器?
- Sass/SCSS 簡介
- Sass/SCSS 基本語法實作
JavaScript 全端開發課程,18 週進度班帶你半年轉職工程師
CSS 預處理器的由來
在過去,CSS 的基本語法與核心機制一直沒有太多變化,大家普遍認為 CSS 的功能就是定義樣式屬性與排版,是一個入門簡單的工具。
隨著網頁開發複雜度逐漸地提高,在開發大型專案時,許多網頁開發者開始發現傳統 CSS 有一些問題:
- 沒有變數與可重複使用樣式的寫法,使得邏輯上相近的樣式設定常需要重複撰寫,導致維護性較差。
- 在模組化開發時,不能採用嵌套(nested)的寫法,導致需要寫很多重複的選擇器。
因為這些重複、可維護性差等缺點,於是開發者就開始思考若是能讓 CSS 像一般程式語言一樣,有變數、函式、迴圈等功能該有多好。
於是,CSS 預處理器就應運而生了!
什麼是 CSS 預處理器?
CSS 預處理器可以說是 CSS 語法的擴充,為了彌補 CSS 在大型專案維護性的不足,CSS 預處理器中新增了變數、混入、繼承、嵌套等寫法,讓開發者可以更有結構地撰寫簡潔、清晰且好維護的 CSS 程式碼。
現今較為主流的 CSS 預處理器有三種,分別是 Sass/SCSS、Less、Stylus,其中的 Sass/SCSS 是目前最多人使用也相對較成熟的選擇。
而這些 CSS 預處理器相對於 CSS 算是較高階的語法,需要另外編譯成 CSS,瀏覽器才看得懂。
零基礎也學得會,從 HTML/CSS/JavaScript 入門程式設計
為什麼要用 CSS 預處理器?
其實上面已經講得差不多了,就像上面說的,CSS 預處理器比較適合用在開發大型專案、多人協作的場景,更能發揮它在可維護性上的效果。
舉例像是透過 CSS 預處理器中變數(variables)的特性,可以在專案建置時統一定義全站的顏色對應表,在後期的開發只要透過類似 $primary-color、$warning-color、$danger-color 這樣的寫法,就能分別輕鬆配上主色、警告色、錯誤色的樣式,甚至有個最大的優點是未來若是全站的顏色對應表要換新,只需要針對這些變數調整就好,不需要痛苦地一個一個 CSS 調整。
但若只開發是一般小型的個人 side project 或者單純的活動案,或許使用傳統的 CSS 就很足夠了,也可以省去要建置編譯 CSS 預處理器相關環境的麻煩。
Sass/SCSS 簡介
講了這麼多 CSS 預處理器的好處,那到底實際上要怎麼用呢?前面提到了三種較主流的 CSS 預處理器,這裡以最常見的 Sass/SCSS 為例來做介紹。
或許你會很疑惑,為什麼 Sass 都跟 SCSS 擺在一起講,他們兩者又有什麼關係?這跟 Sass 的發展史有關,2007 年誕生的 Sass,是最早的 CSS 預處理器。舊版的 Sass 採用 Ruby 語言編寫,最初為了配合 HAML(一種縮排式的 HTML 模版語法)的寫法,也設計成縮排式的寫法,所以在 Sass 的語法中不寫大括號及分號,像是以下這一段 Sass 語法(官方範例):
<p>CODE: https://gist.github.com/ackent/b3ea431306a5435c6448964fd1cebc16.js</p>
編譯後會產生如下的 CSS:
<p>CODE: https://gist.github.com/ackent/45c596c7350c2413a825fd45b7239e15.js</p>
雖然這種縮排的風格可以減少一些程式碼,但卻因為無法兼容舊有的 CSS 語法,所以一開始沒有後來出現的 Less 那麼普及。後來受到 Less 影響,Sass 發展出兼容 CSS 的新語法就稱為 SCSS,也就是說在 SCSS 中直接撰寫 CSS 也是完全沒有問題的,因為在 SCSS 的語法中有大括號及分號,以前面的例子像是這樣:
<p></p>CODE: https://gist.github.com/ackent/a6a8e9c6fae1f03e9dd6bc863802ae03.js<p></p>
這樣的寫法其實跟原本的 CSS 沒有太大的差異,又多了許多變數、mixins、nested rules 等更豐富的語法,這也是為什麼 Sass/SCSS 越來越受歡迎的原因之一。
Sass/SCSS 基本語法實作
關於 Sass 的詳細語法教學有許多文章中都有介紹了,這邊就簡單用幾個範例示範 CSS 預處理器的幾個常用的特性:變數(Variables)、函式(Functions)、嵌套(Nesting)、混入(Mixins)、共用(Extends)。
建立編譯環境
在開始前首先還是要了解怎麼將 Sass 編譯成 CSS,根據官方安裝方法 選擇最基本的在 CLI 安裝 Sass 編譯器,在終端機輸入以下這行:
npm install -g sass
安裝好後在某個資料夾底下建立一個 input.scss 的檔案,並且在該檔案的位置下終端機執行這行:
sass –watch input.scss output.css
這是將 input.scss 編譯成 output.css 的指令,而其中的 –watch 可以 hot-reload 接下來後面要測試的語法,直接針對 input.scss 檔案每次的變化來編譯成 CSS 檔案。
變數(Variables)
前面有提到,若是要定義全站的顏色對應表(color-map)、字型相關樣式等等,任何你認為未來會一直重複使用到,並且需要定義統一的 CSS 屬性,就可以使用變數,概念與寫 JavaScript 時定義變數是一樣的。如下面例子分別是使用變數的 SCSS 及編譯後的 CSS:
<p>CODE: https://gist.github.com/ackent/78a11cd5fbedb4f70779a121dc3b108b.js</p>
<p>CODE: https://gist.github.com/ackent/fb6bb7788eccb3b0cdf9b8a621b3e280.js</p>
語法很單純,就是以一個 $ 的前綴加上變數名稱就可以組合成一個變數。
函式(Function)
除了變數之外,讓開發 Sass 更像在寫程式的特性就是 function 了,可以將重複使用的長度、大小計算等邏輯,抽象化成 function 的形式,如下面例子分別是使用 function 的 SCSS 及編譯後的 CSS:
<p></p>CODE: https://gist.github.com/ackent/c703bcfd2a809500b52cd5374dbd1cd8.js<p></p>
<p></p>CODE: https://gist.github.com/ackent/7945fe094ed77306b1776564b63ea086.js<p></p>
這邊實作一個指數函式 pow(),可以看到語法是以 @function 為開頭加上函式名稱及參數,概念與一般寫程式一樣,甚至也可以用 for 迴圈、if/else 判斷式,最後將結果值 return 給呼叫這個函式的地方。
嵌套(Nesting)
當我們在撰寫 HTML 時,可以輕易的寫出 DOM 之間嵌套的階層結構,但在傳統的 CSS 做不到,需要重複寫許多父元素選擇器。
這問題可以使用 Sass 中嵌套的特性來解決,以下是 SCSS 及編譯後的 CSS:
<p></p>CODE: https://gist.github.com/ackent/242d76d61659ffe7e840ef4828f60a67.js<p></p>
<p></p>CODE: https://gist.github.com/ackent/f9d5293255b5d45e3cf092fed95cb370.js<p></p>
從這個例子可以看到編譯後的 CSS 就像原本提到的問題,需要寫許多 nav 這個父元素,但在 Sass 中可以直接像在寫程式一樣將父子元素這樣一層一層包起來。
混入(Mixins)
當有一段 CSS 設定經常性地被重複使用,甚至可以根據不同「參數」對應出相似的樣式,就可以將這段設定獨立寫成一個 mixin 方便取用,參考下面的例子:
<p></p>CODE: https://gist.github.com/ackent/91e901727b6144afc1cb184e73250b41.js<p></p>
<p></p>CODE: https://gist.github.com/ackent/d3f810bc2346c1b5a151c30e04bdade8.js<p></p>
語法是用 @mixin 開頭,並可以帶入參數及預設值,其中也可以寫 if/else 判斷式等寫法。設定好之後就可以在需要這一段 mixin 的選擇器中使用 @include 引入。
mixin 可以說是 Sass 中一個強而有力的寫法,甚至它還可以搭配 @content 的寫法傳入整段 CSS,想要看更多 mixin 的例子的話可以參考 Bootstrap 中 mixin 的原始碼,裡面有更多深入的語法及應用。
共用(Extends)
有一種狀況是當有一個選擇器需要包含另一個選擇器中的所有樣式,或是許多選擇器具有相同樣式時,為了避免要一直重寫同一組相同的 CSS 樣式,在 Sass 中我們可以使用 Extends 的寫法。
上面這段話稍微有點抽象,換句話說就是 Extends 可以將所有相同樣式的內容合併,直接舉個例子:
<p></p>CODE: https://gist.github.com/ackent/a72f35659aaeb81540c493076ce440e8.js<p></p>
<p></p>CODE: https://gist.github.com/ackent/80f09c5f2094510467e5aa6e42086fea.js<p></p>
從上面的例子中可以看到,將要共用的樣式用 %message-shared 包起來,並在其他要共用這一段樣式的地方使用 @extend %message-shared,這邊可以注意到使用 Extends 的 Sass 語法編譯成 CSS 後,在 CSS 中會將共用的部分統一集中管理。
另外也可以注意到在上面的 SCSS 中有另一段共用屬性 %equal-heights 沒有被其他人共用,在編譯成 CSS 後並不會產生,所以這個寫法又被稱為「佔位選擇器(placeholder selector)」。
Mixins or Extends
Mixins 與 Extends 兩者的概念蠻相近的,由於兩者都可以拿來做相同樣式的包裝,所以兩者的使用時機很容易讓人搞混。
舉個例子將上面 Extends 的例子若用 Mixins 改寫:
<p></p>CODE: https://gist.github.com/ackent/c6dc03a70e6b13344a18d6b89731c34c.js<p></p>
<p></p>CODE: https://gist.github.com/ackent/c3101858225764b7d20ae84adeedff65.js<p></p>
其中可以看出一個明顯的差別就是,編譯後的 CSS 會在每一個選擇器都插入 mixin 中重複的部分,在這種完全相同的樣式時,使用 Extends 處理會更好,而 Mixins 就拿來處理可以動態使用「參數」的類型。
在官方文件中也有對這個疑問作出解釋,另外也舉了一個 Extends 在 BEM 設計方法中的應用,有興趣深入了解的讀者可以研究研究,這邊就不贅述。
其他特性
Sass 中還有許多特性像是可以將單個檔案切成多個 modules 引入、使用各種資料型別(Strings、Lists、Maps等)、內建 functions 等,而上面介紹的幾種語法也都有相對應深入且複雜的應用,這邊只淺淺的點出最入門的部分。
其他更深入的語法建議仍可以參考官方文件,應用的部分也可以參考一些知名大型專案怎麼使用,像是 Bootstrap 的原始碼中就有用到許多 SCSS 的寫法。
總結
隨著網頁開發越發複雜,CSS 的可維護性也越顯重要,但在 CSS 語法仍然受限的狀況下,發展出了 CSS 預處理器來擴展更多有彈性的寫法。
本篇文章從介紹 CSS 預處理器的內容與使用時機,到實際利用 Sass/SCSS 介紹幾個基本語法來展示其特性,希望能讓讀者對 CSS 預處理器相關的入門知識有更多了解。
(本文作者是 ALPHA Camp 課程學期二助教:前端工程師Dez)
參考資料
- Sass documentation @ Sass 官方文件
- Sass Basics @ Sass 官方文件
- 浅谈 CSS 预处理器(一):为什么要使用预处理器? @ cssmagic
- 什麼是CSS 預處理器? @ changtsuiling
- 浅谈css预处理器,Sass、Less和Stylus @ 牧曈
- CSS preprocessor 介紹,與 SASS 入門分享 @ wantingj