BEM 學習

tags: OKR 自主學習 SCSS/BEM
2020/07/11(Update)

7/11學習內容

學習來源:
BEM官方文件
youtube資源學習


什麼是BEM?
  1. 以Block結構來命名Html Class Name。
  2. 全名叫Block/Element/Modifier。
  3. Block:一個區塊包覆相同的內容結構,例如下方卡片範例,卡片最外面的一層就叫Block。
  4. Element:卡片裡面的各項內容抽出來就叫element,例如圖片img/標題title/描述desc/按鈕button。
  5. Modifier:代表修飾符號名稱,比較簡單的說法是這個Element狀態事件發生或是形體上的改變、不同的類型,例如我們專案上常會寫到按鈕被active或是卡片有分light/dark類型,如下範例。
Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

BEM命名範例

<div class="card card--light"></div>
<div class="card card--dark"></div>
形體上的改變、不同的類型

用BEM的好處是什麼
  1. 雖然感覺Class命名變長,但整體結構能讓沒寫這專案的人都能快速理解。
  2. 命名很長的問題,透過搭配撰寫SCSS就可解決。
  3. 很多命名會重覆的區塊就可以模組化共用使用。
  4. 變的更好維護。
BEM基本寫法

如果是Element:blockname__elementname ( 二個下底線 _ _ )

<div class="card__title"></div>

如果是Modifier:blockname__elementnameModifierStatus ( 二個連字符 - - )
過往都是直接寫active/hidden/success 等寫法,BEM寫法換成以下方式

<div class="card__button card__button--active"></div>
<div class="card__button card__button--is-active"></div>
<div class="card__button card__button--is-hidden"></div>
使用SCSS撰寫BEM樣式

當Html架構寫好後,開始撰寫BEM樣式,結合SCSS寫法

/* SCSS結構 */

.card{
 &__title{.....}
 &__button{
     //......
     &--active{.......}
 }
}
/* CSS編譯結果 */

.card__title{....}
.card__button{.....}
.card__button--active{.....}

Classname也可以加上 ' - ',使用前缀

<form class="site-search  site-search--full">
    <input type="text" class="site-search__field">
    <input type="Submit" value ="Search" class="site-search__button">
</form>
/* SCSS結構 */
.site-search{}
.site-search__field{}
.site-search__button{}
.site-search--full{}
BEM最好的寫法

在撰寫時,除了更換命名的方式,但撰寫SCSS結構時也需要一併思考,整個結構先以一個Block命名開始,其它必須統一一致,例如:

<button class="button">基本按鈕</button>
<button class="button button--state-success">成功按鈕</button>
<button class="button button--state-danger">警示按鈕</button>

我們應該怎麼寫SCSS?

/* 1.首先先寫好預設按鈕的結構 */
.button{
    border-radius: 3px;
    padding: 7px 12px;
    border: 1px solid #D5D5D5;
    font-size:16px;
    text-align:center;
    
    /* 2.在把Modifier所需狀態使用的SCSS寫出來 */
    &--state-success{
        color: #FFF;
        background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x;
        border-color: #4A993E;
    }
    &--state-danger{
        color: #900;
    }
}
撰寫時遇到的問題紀錄

問題一

實際撰寫時,當使用Modifiter時active,雖然搭配SCSS天衣無縫,不需要寫太長的名稱,但若是使用在JS上時,你必須要將完整的Classname寫上去,雖然一樣名稱太長,但一樣若能讓每個人容易理解之優點來說還是大過於此缺點,也或許是自己可能還沒尋找到最佳方法。

$('.card__button').addClass('.card__button--active');

問題二

實際撰寫時一定要整個結構一致,否則會吃不到子層的樣式,遇到問題是希望在同層加上同一結構但不同類型的Class狀態。

例如這張卡片需要dark(暗色系)或是light(亮色系)。下方範例會發什麼事情,.card.light的樣式會吃不到底下的.card__item樣式,意思是CSS沒辦法吃到(.card.light .card__item),猜測應該是撰寫BEM規則時,SCSS在編譯時可能沒法整併。

/* 1.light or dark 非BEM寫法 */
<div class="card light">
    <div class="card__item"></div>
    <div class="card__item"></div>
    <div class="card__item"></div>
</div>
<div class="card dark">
    <div class="card__item"></div>
    <div class="card__item"></div>
    <div class="card__item"></div>
</div>
/* 2.當撰寫時,SCSS to css 吃不到__item */
.card{
    &.light{
        &__item{
        ........
        }
    }
    &.dark{
         &__item{
        ........
        }
    }
   
}

改寫方法:

/* 1.加上modifier類型 */
<div class="card card--light">
    <div class="card__item"></div>
    <div class="card__item"></div>
    <div class="card__item"></div>
</div>
<div class="card card--dark">
    <div class="card__item"></div>
    <div class="card__item"></div>
    <div class="card__item"></div>
</div>
/* 2.先寫好card基本結構,並在給予light/dark增加顏色樣式等內容 */
.card{
    //3.這裡寫card基本結構
    .....
    //4.再來針對light/dark寫樣式
    &--light{
        color:#ffffff;
    }
    &--dark{
        color:#000000;
    }
    .__item{
     .....    
    }
}

這樣每個class在同一個card Block底下結構均都不受影響,不需要為了某個結構在重覆改寫。

問題三

在查看BEM官方文件CSS層疊繼承所帶來的問題,發現了原來自己撰寫時也可能會犯下的不好習慣,有些地方過度濫用CSS層疊繼承,覆蓋原有編寫的樣式問題。下方的圖片反而造成樣式不斷被重覆改寫,程式碼太多/浪費等問題。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

CSS層疊繼承

改寫方法:
如同模組化的概念,樣式應該要更加彈性,應該是要可獨立/可重用/不受任何父層影響/更好維護。