透過 BEM、SMACSS、OOCSS、Atomic CSS 簡化樣式開發流程、減少維護成本 從把妹角度理解前後端如何和平相處

me
林彥成
2022-09-07 | 4 min.
文章目錄
  1. 1. CSS 設計模式
    1. 1.1. 減少命名與維護成本
  2. 2. BEM 命名設計模式
  3. 3. SMACSS (Scalable and Modular Architecture for CSS)
  4. 4. OOCSS (Object Oriented CSS)
  5. 5. Atomic CSS 設計模式
    1. 5.1. 簡化開發流程
    2. 5.2. 導入 Atomic CSS 可能的問題
    3. 5.3. Utility-First CSS

本篇文章將提到怎麼透過 BEM、SMACSS、OOCSS、Atomic CSS 的特性來:

  • 縮短開發時間
  • 減少需維護的程式碼
  • 結構與樣式

CSS 選擇器和規則們就像女孩化妝桌上的化妝品們,桌上總是放著各個種類,數也數不清大罐小罐擠的噴的擦的,在沒有預備知識和整理規劃的情況下,若要一個男孩子短時間搞清楚簡直是天方夜譚。

當交接新專案的時候看到幾千行的樣式檔大概也是這樣的心情,一般專案在未規範的情況下,通常都會發展為幾千甚至幾萬行 CSS 的狀態。

如果還不知道面試前端可以問什麼,歡迎參考:

CSS 設計模式

這篇文章將簡單介紹四種 CSS 常見命名原則與設計模式方法論

  • BEM: 訂定可以遵循的規範
  • OOCSS: 將容器與內容用 “物件” 的概念進行管理
  • SMACSS: 依照結構將樣式檔分成五類進行撰寫
  • Atomic CSS: 撰寫原子化樣式

無論最終選擇使用哪種方法都將受益於更加結構化的 CSS,風格也更容易被團隊所理解和適應,目標:

  1. 可預測性 (Predictable)
  2. 可重複使用性 (Reusable)
  3. 易維護性 (Maintainable)
  4. 可擴充性 (Scalable)

減少命名與維護成本

寫樣式檔最大的維護性問題會出現在:

  • 多人協作時的命名重複,用 BEM 或是 styled-component 可以去避免
  • 陳年專案不確定到底哪些樣式檔還有在使用

針對命名上一般會有三個重點:

  1. 看到名字就知道效果
  2. 看到名字就知道用在何處
  3. 看到名字就可以理解結構上的關係

BEM 命名設計模式

CSS 在相關工具不太普及的時候就出現了 BEM 命名規則:

  • 區塊 (Block)
  • 元素 (Element)
  • 修飾符 (Modifier)

header__title--hover 代表 header 中的 title 在 hover 時的狀態

這樣的命名方法就像是女孩的化妝品們按照分類放進化妝櫃中,透過規範提供了統一又易讀的原則,有原則可預測性就高,就算什麼寫法都不去背誦,也可以透過這樣的原則來理解當時的想法。

透過模組化的概念,樣式不會依賴其他元素,區塊組合的概念也可以重用寫過的樣式。

SMACSS (Scalable and Modular Architecture for CSS)

將樣式檔依照結構上分成五類進行撰寫,分別是 Base、Layout、Module、State、Theme

  1. Base: 全域設定,未使用 Class 僅設定像 h1~h6、body、a 等等元素,通常可以使用 Normalize 來正規化各瀏覽器預設的樣子,也可以選擇撰寫 Reset CSS 來處理
  2. Layout: 網頁架構的部分,ex. header、footer、sidebar
  3. Module: 是獨立且可以重用的元件,舉 bootstrap 的例子 <button type="button" class="btn btn-primary">Primary</button>,當不需要某個元件時可以安全的移除樣式檔
  4. State: 元件的狀態,像是被按到的按鈕
  5. Theme: 設定網站主題,像是暗黑模式

OOCSS (Object Oriented CSS)

主要是兩個概念結構與樣式分離 (Separate structure and skin)、容器與內容分離 (Separate container and content)

  1. 分離結構與樣式

.btn: 結構
.btn-primary: 樣式

1
2
3
4
5
6
7
8
9
10
11
12
13
/* 合併結構與樣式 */
.login-button {
color: blue;
padding: 10px 20px;
}

/* 結構與樣式分離 */
.btn {
padding: 10px 20px;
}
.button-primary {
color: blue;
}
  1. 分離容器與內容,Bootstrap 的格線系統 .col-x 就是用這種方式命名的,容器與內容分離時,容器和內容的重用性就會變高。不過像是 card 跟 card-body 就不需要分離,因為 card-body 獨立也無法使用。
1
2
3
4
5
6
7
8
9
10
<div class="row">
<div class="col-12">
<div class="content"></div>
</div>
</div>

<!-- 不須分離 -->
<div class="card">
<div class="card-body"></div>
</div>

Atomic CSS 設計模式

最近讀了一篇 Facebook 重新設計前端專案的文章,Facebook 是一個功能非常多元的網站,除了動態牆外還涵蓋了社團、粉專、電商平台…等等,所以原來的架構不再適合,因為:

  • 對於初次進入網站的使用者來說,大部分的程式碼在剛開始都是不需要被載入的
  • 近年需開始實作 dark mode 來提供更好的體驗

原子化樣式是將各種可能的基礎情況都寫成一個 class 然後搭配變數讓整個樣式的撰寫能夠透過組合的方式進行。

缺點在於命名會是一個公版需要大家去習慣,優點是不再需要額外重寫相關的 CSS。

簡化開發流程

原來的開發流程,要處理兩個檔案:

  • 寫 HTML tag
  • 開 CSS 樣式檔寫樣式
  • 把剛寫的 class 塞回 HTML tag

Atomic CSS 的開發流程,只要提早建立原子化樣式像 .mt-3 後續只需要處理一個檔案:

  • 寫 HTML 的同時就直接加上 <span class="mt-3">test</span>

為了加速大家開發 Bootstrap 不只定義好了相關元件也提供了過多預設的公版樣式,需要理解後透過覆蓋或是增加權值去修改,感覺有種比誰道行高的感覺。

如果能夠只導入原子化樣式的部分,理論上:

  1. 簡化開發流程
  2. 減少命名與維護成本
  3. 樣式檔的成長也會較接近對數曲線
1
2
3
4
5
6
7
8
9
10
11
12
13
.m-3 {
margin: 1rem !important;
}

.mt-3,
.my-3 {
margin-top: 1rem !important;
}

.mr-3,
.mx-3 {
margin-right: 1rem !important;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.0/css/bootstrap.min.css" />
<style>
.form-wrapper {
padding: 1rem;
margin: 0.25rem;
background-color: #007bff;
}
.form__input {
margin: 1rem;
}
</style>
</head>
<body>
<form class="form-wrapper">
<input class="form__input"></input>
</form>
<!-- Atomic CSS -->
<form class="p-3 bg-primary m-1">
<input class="m-3"></input>
</form>
</body>
</html>

開始使用 Atomic CSS 後我們會發現:

  • 因為不用再花心思在命名,像是 form-wrapper 這種命名將不再需要
  • 樣式檔的成長速度變成接近對數的曲線
  • 可以更快、更小幅度、更安全的修改全站樣式
  • 更方便的修改網站主題 (主視覺)
  • 移動標記的同時也移動了樣式

導入 Atomic CSS 可能的問題

  • 建立時 class 命名一樣需要 convention,需花時間建置符合團隊習慣的命名
  • 如果是用 bootstrap 4 需要時間熟悉
  • 很特殊的狀況其實還是需要走回 BEM 命名風格去客製化少部分樣式

Utility-First CSS

  • Tailwind CSS
  • Primer

舉例來說 Primer、Tailwind CSS 主要是縮減大家打字的字數,並且重用基礎的樣式來達到縮減 CSS 體積的效果。

.mt-1: 對應 margin-top: 0.25rem;
.my-2: 對應 margin-top: 0.5rem; margin-bottom: 0.5rem;

1
2
3
.mt-1 {
margin-top: 0.25rem;
}

喜歡這篇文章,請幫忙拍拍手喔 🤣


share