MonkeyBinBin

被程式設計的猴子

BEM SCSS

使用 BEM 與 SCSS 讓 css 不再眼花撩亂


命名規則一直是寫程式的重點,當然網站樣式也是有一樣的問題。最近看到幾個方式覺得可以參考,就在某個專案中實作了這部份。的確在樣式的調整上變的快速而且容易許多。配合客戶東改西調不再是問題!?(笑)

程式開發的「命名」一直是大家討論與關注的重點。透過命名我們可以獲得那些訊息?什麼樣的命名是好的?透過一致性的命名規則讓程式碼易讀、易懂並且可重用,讓開發和維護更有效率。我認為要使用什麼樣的命名規則應該要依照需要與團隊習慣來決定。沒有什麼命名方式一定是好的,只要符合需要就是好的。當我們在開發網站時,整個網站做下來會有非常多的樣式設定,如何達到樣式的共用與結構化,一眼就能看出樣式的用途與義意是非常重要的,這也是我為什麼會選擇 BEM 的原因之一。

常見樣式命名規則

  1. OOCSS
  2. SMACSS
  3. BEM

上述三種方式為目前比較常見的樣式命名規則,以下會做簡單的介紹。

OOCSS 簡介

OOCSS(Object Oriented CSS)字面意思是物件導向的CSS,追求元件的重用,樣式名命比較抽象。

主要原則:

  1. Separate structure and skin(分離結構和主題)
  2. Separate container and content(分離容器和內容)

SMACSS 簡介

SMACSS(Scalable and Modular Architecture for CSS),模組化可擴展架構,主要目標為更語義化的 html 與 css,並且降低對依賴特定的 html 結構。

主要原則:

  1. Categorizing CSS Rules(為css分類),Base(基礎)、Layout(佈局)、Module(模組)、State(狀態)、Theme(主題)
  2. Naming Rules(命名規則),考慮用命名來表現樣式的分類,例如使用 l- 或 layout- 的字首來表現 Layout 這個類別的樣式
  3. Minimizing the Depth of Applicability(最小化適配深度),盡可能使用短的、不限定 html 結構的選擇符

BEM 簡介

BEM(Block, Element, Modifier),透過 Block、Element、Modifier 來描述頁面,從樣式名稱就可以看到一些有用的資訊,使程式碼更易於維護。

Block 是頁面中獨立存在的區塊,可以在不同場合下重用。每個頁面都可以看做是多個 Block 組成。(圖片來源:https://en.bem.info/methodology/key-concepts/) bem block

Element 是構成 Block 的元素,只有在 Block 內才具有意義,是依賴於 Block 而存在。(圖片來源:https://en.bem.info/methodology/key-concepts/) bem element

Modifier 是用來描述 Block 或 Element 的屬性或狀態。同一個 Block 或 Element 可以有多個 Modifier。(圖片來源:https://en.bem.info/methodology/key-concepts/) bem modifier

命名方式區分為3種:

  1. suit - http://suitcss.github.io/
    .BlockName {}
    .BlockName--modifierName {}
    .BlockName-elementName {}
    .BlockName-elementName--modifierName {}
  2. inuit - https://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/
    .block-name {}
    .block-name--modifier-name {}
    .block-name__element-name {}
    .block-name__element-name--modifier-name {}
  3. yandex - http://bem.info/
    .block-name {}
    .block-name_modifier_name {}
    .block-name__element-name {}
    .block-name__element-name_modifier_name {}
    目前我選用的是 inuit 的命名方式,我的感覺這個規則比較單純。modifier 前面固定加上 --,element 前面固定加上 __。

主要原則:

  1. "不可"使用 css 標籤選擇器和 id 選擇器(例:h3, .demo li, #demo)
  2. Block 不能影響所在環境,不應該設置任何會影響外部的 style(例:margin)
  3. Block 和 Block 之間可以不分層次的嵌套
  4. Element 和 Element 之間可以不分層次的嵌套
  5. Element 一定是屬於 Block 的一部份,這表示 Element "無法"定義層次結構(錯誤範例:block__element1__element2)
  6. 如果某段樣式可能會重覆使用,且不依賴於其他組件時,就應該建立一個 Block
  7. 如果某段樣式在沒有 Block 的情況下無法使用,就應該建立一個 Element
  8. Modifier 用來描述 Block 或 Element 的外觀、狀態與行為。

為何我要選擇 BEM ?

  1. 從命名可看出樣式的用途,明顯能夠區分出樣式間的關聯
  2. 命名規則明確,只針對區塊做樣式的設定,比較不會影響到區塊以外的樣式
  3. 樣式名稱比較不容易有衝突(因為名稱很長,有人可能覺得這是缺點),取名的時候不用想破頭
  4. 避免出現太過複雜的選擇器(複雜的選擇器範例:.demo > li:not(.hello) > a ~ *.hi),比較容易看的懂(這點其他2個命名規則應該也能達到)

BEM 搭配 Sass

利用 Sass 的 Nesting 與 & 符號來簡化樣式的寫法
不需要一直重覆寫 Block 與 Element 名稱

使用 BEM 命名規則搭配 Scss 開發之樣式

// 頁面整體的 Layout
.wrapper {
  display: flex;
  height: 100%;
  // 左側選單
  &__menu {
    width: 200px;
  }
  // 右側主要內容
  &__content {
    background: white;
    width: 100%;
    padding: 10px;
  }
}

// 側邊選單的樣式
.side-menu {
  display: flex;
  flex-direction: column;
  background: #054b7c;
  color: #fbd300;
  // 選單內的 item 樣式
  &__item {
    padding: 10px 20px;
    background: #054b7c;
    cursor: pointer;
    transition: background linear .3s, border ease-in-out .2s;
    // 選單內的 item 被選中的樣式
    &--active{
      color:#054b7f;
      background: #fbd300;
      border-left: 8px #fc5801 solid;
    }
    // 選單內的 item 有滑鼠移至上方時的樣式
    &:hover {
      color:#054b7f;
      background: #fbd300;
      border-right: 8px #06F0A9 solid;
    }
  }
}

轉譯為 css 後的結果(符合 BEM 規則)

.wrapper {
  display: flex;
  height: 100%;
}
.wrapper__menu {
  width: 200px;
}
.wrapper__content {
  background: white;
  width: 100%;
  padding: 10px;
}

.side-menu {
  display: flex;
  flex-direction: column;
  background: #054b7c;
  color: #fbd300;
}
.side-menu__item {
  padding: 10px 20px;
  background: #054b7c;
  cursor: pointer;
  transition: background linear .3s, border ease-in-out .2s;
}
.side-menu__item--active{
  color:#054b7f;
  background: #fbd300;
  border-left: 8px #fc5801 solid;
}
.side-menu__item:hover {
  color:#054b7f;
  background: #fbd300;
  border-right: 8px #06F0A9 solid;
}

完整的程式碼範例在這裡哦!!

感想

命名規則只是一個輔助的方式,盡可能符合。但如果有特殊情況可視狀況來做調整。工具是用來幫助自已不是用來困住自已的。