Css設計心法教學-SMACSS、OOCSS、BEM


前言:
其實網路上已經有很多文章在介紹SMACS、OOCSS、BEM,而這篇文章存在的目的,就是以一個新手的角度來試著理解這三大架構如何幫助我們管理CSS。

OK,在開始介紹前,我們必須了解到這些設計方法存在的目的是為了方便管理Css所衍伸出來的。而所謂好的CSS撰寫該包含哪些特性呢?
這邊引用Kuro 大大之前分享-漫談 CSS 架構方法 中提到的幾點概念

良好Css架構應包含
1.預測-Predictable
2.複用-Reusable
3.維護-Maintainable
4.延展-Scalable

先記住這幾項原則後,我們來分別簡略介紹這三大設計法則
  • OOCSS (Object OrIEnted CSS)
設計基本原則有兩大點:
  1. 結構與樣式分離(Reusable)
  2. 內容與容器分離(Scalable)

結構與樣式分離 參考卡斯柏老師圖解
說明:
結構可以看成button中的width、height、padding等基本結構;樣式則可以看成外觀表現上如:border、background-color
案例:
--從下面程式碼,我們可以發現button、box有部分css內容是重複的,這樣撰寫的話會造成日後若要調整顏色、外框粗細等樣式不便。此外,重複的css也造成檔案肥大。
#button {
  width: 200px;
  height: 50px;
  padding: 10px;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

#box {
  width: 400px;
  overflow: hidden;
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}
因此,我們藉著套用結構與樣式分離原則,來試著改寫下面這段Css
//css程式碼的複用性就提高了
.button {
  width: 200px;
  height: 50px;
}

.box {
  width: 400px;
  overflow: hidden;
}

.style {
  border: solid 1px #ccc;
  background: linear-gradient(#ccc, #222);
  box-shadow: rgba(0, 0, 0, .5) 2px 2px 5px;
}

內容與容器分離 卡斯柏老師講解
說明:將HTML結構與Css盡量切割開來,以可共用的css selector來設計css
案例:
我們先定義header下的h1的樣式
.header h1{
    font-size:2rem;
    color:#00cc99;
}
這時footer中若也要套用相同文字大小,但不同顏色的文字的話,你可能會這樣寫
.header h1,.footer h1{
     font-size:2rem;
     color:#00cc99 ;
}

.footer h1{
  color:blue;
}
你會發現撰寫上,需要再針對顏色再多撰寫css,如此重複性撰寫未來在維護上是一種問題,因此我們可以這樣改寫
//html部分
<div class="header fontSize-l"></div>
<div class="footer fontSize-l"></div>

//css部分
.fontSize-l {
    font-size: 2rem;
}

.header {
    color: #00cc99
}

.footer {
    color: blue;
}

  • SMACSS (Scalable & Modular Architecture for CSS)
--由Jonathan Snook提出的CSS設計理論。其主要原則有3條:

  1. Categorizing CSS Rules(為CSS分類)
  2. Naming Rules(命名規則)
  3. Minimizing the Depth of Applicability(最小化適配深度)

依結構來區分
--共分為五種:base、layout、module、state、theme
  • Base:主要拿來設計全站基礎樣式,也包含CSS Reset。
命名方式:只會用element tag selector
例如:
html{
background: $bg-white;
}
h1,h2,h3{
margin: 1em 0;
}
參考:pure.css base 連結

  • Layout
將網頁切成不同區塊,諸如header、sidebar、content。因為這些大型區塊在網頁上通常都是獨立出現,故命名上可以使用ID。但若遇到重複區塊,可以使用Class層疊特性,將屬性權重往上提升。
#article {
width: 80%;
float: left;
}

#sidebar {
width: 20%;
float: right;
}
// layout固定大小(compare to 滿版)

.l-fixed #sidebar {
width: 200px;
}
命名原則:
1.用l-或layout-這樣的前綴,例如:.l-header、.l-sidebar
2.減少語意化命名(目的:可以挪為其他專案使用如下)
.booklist{
padding: 10px;
}

// 調整成可通用
.list{
padding: 10px;
}

  • Module
跟Layot相似,也是頁面上的區塊(較小的區塊內容如:navbar),這邊的區塊更為獨立,可以適用不同專案。
命名方式:只能用class selector命名,並且使用dash分隔。
如:modal-body、modal-img(子模組設計概念,基本上就是bootstrap設計概念)
禁止使用ID、element selector
// 用 dash 分隔 class (subclassing/submodule)

.modal-body {
width: 100%;
}

.modal-header {
height: 50px;
width: 100%;
}


  • State
描述元件狀態,因此命名上,針對該狀態的描述越精準越好。State和Module最大差別在於:State可以覆蓋Module/Layout的Style、State通常會搭配JS做使用
命名方式:用is-前綴,例如:.is-active、.is-hidden
.tab {
    background-color: purple;
    color: white;
}

.is-tab-active {
    background-color: white;
    color: black;
}

  • Theme
針對網站主視覺色彩、文字大小樣式做定義
命名方式:用theme-前綴,例如.theme-a-background、.theme-a-shadow。
// in module-name.css
.mod {
    border: 1px solid;
}

// in theme.css
.mod {
    border-color: blue;
}

優點:
根據其結構化管理CSS、可以增加專案協作可維護性(可重用性、可延展性)
缺點:
Css較為龐大

通常會搭配Sass處理器一起執行~
說明:Bem就是由區塊(block)、元素(element)、修飾符(modifier)所組成
目的:幫助後續管理程式碼,了解區塊與元素之間是否有關係讓你在瀏覽HTML CODE時,能夠透過觀察class,就能了解你的CSS架構,不用再回去追CSS Code才辨別得出哪些是Layout、Modifier
 
一、寫法介紹:
.block{} //區塊 (Block)
.block__element{} //元素 (Element)
.block--modifier{}//修飾符(Modifier)
 

  • 區塊(Block)
--網頁上單獨可拿來複用的區塊,如Bootstrap中Components區塊設計概念。
舉個簡單例子:Card元件就是一個區塊元件
小結:
通常為頁面上獨立元件,可以被重複使用

  • 元素 (Element)
我們由下面這張圖片來說明一下,可以發現元素是屬於區塊中底下。重點不能單獨拿出去別的區塊使用,專屬於這個Menu區塊。例如:
<div class="card" style="width: 18rem;">
  <img src="..." class="card-img-top" alt="...">
  <div class="card-body">
    <h5 class="card-title">Card title</h5>
    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
    <a href="#" class="btn btn-primary">Go somewhere</a>
  </div>
</div>


小結:
需配合block使用,主要用來描述目的

 
  • 修飾符(Modifier)
當區塊或元素因為狀態而改變時,就在後面加上雙中線--來辨識它是修飾符,
像是下圖選單的部份,當被點選時為了要讓使用者了解該元素有被點選,
所以就會用javascript動態加入class為.menu__item--active
主要用來描述狀態 EX:顏色、大小

例如:
<li class="nav-item active">
   <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
 

二、什麼時機不會需要用到BEM?(以下內容摘入自洧杰老師--Sass教學BEM 設計模式)
 
2.1可以獨立成為一個class,具有複用性
當我們網站內容有個CSS設定時常會用到其他地方時,就會把他獨立成一個class名稱提升他的複用性。
EX:清除浮動 .clearfix{clear:both},
或者是置左功能.pull-left{float:left}。
 
2.2並不是所有的元素都要遵守BEM的規則
假設來說我.content裡面有個選單元素,
所以你就寫了.content__menu,但你必須去了解這個元素是否會在表尾、側欄其他地方出現,如果會的話,那就應該是從.menu當做一個區塊來向內延伸設計把它變成一個Module模組。(SMACSS設計規範)
 
3.搭配scss語法撰寫

.media{
    width: 100px;
    &__input{
        width: 100px;
        &--color{
            background: green;
        }
    }
}


結論:
強烈建議讀完整篇文章後,一定要拿相關作品來設計,如此才能確實掌握設計精髓。


留言