Nic Lin's Blog

喜歡在地上滾的工程師

使用 BEM 之後的 CSS 書寫規範

我們平時最開始學習寫 CSS 代碼的時候,我們都是這麼寫的:

.main-part .tabs {
  /*...*/
}

其實這樣的寫法是不好的,因為它過度的與頁面中的某一部分耦合了。我們在軟件工程的思想中追求的就是解耦。

BEM 風格不只一種

BEM 的命名規範不是死的,可以參考 bem-conventions

這裡有一些可供選擇的基於 BEM 命名約定的方案。

Two Dashes style(雙連字符風格)

block-name__elem-name--mod-name

  • 名字全部使用小寫。
  • BEM 實體的名稱中的每一個單詞使用一個連字符分隔。
  • 使用雙下划線(__)將元素的名稱和模塊的名稱分離開。
  • 使用雙連字符(–)分隔 Boolean 類型的修飾符。
  • 不使用 key-value 類型的修飾符
  • 重要提示!在注釋中,雙連字符被視為注釋的一部分,因此在文檔驗證時,雙破折號可能會引起錯誤。HTML5 Specification

CamelCase style(駝峰命名風格)

MyBlock__SomeElem_modName_modVla

這種風格的命名方案的不同點在於,在 BEM 實體中分隔單詞時使用駝峰命名法代替了一個連字符(-)。

“Sans underscore” style(無下划線風格)

blockName-elemName--modName--modVal

名稱使用駝峰命名法書寫。 元素名稱與模塊名稱使用一個連字符(-)分隔。 修飾符使用雙連字符(–)與模塊或元素分隔, 修飾符的名稱和值使用雙連字符(–)分隔。 重要提示!

在注釋中,雙連字符被視為注釋的一部分,因此在文檔驗證時,雙破折號可能會引起錯誤。HTML5 Specification

BEM 說明(這裡用 Two Dashes style(雙連字符風格))說明

在這邊使用 BEM 的命名規範,每行 CSS 代碼都只有一個選擇器

BEM代表 區塊(block),元素(element),修飾符(modifier)」,我們常用這三個實體開發組件。

在選擇器中,由以下三種符合來表示擴展的關係:

-   dash :僅作為連字符使用,表示某個塊或者某個子元素的多單詞之間的連接記號。
__  Two underline:雙下划線用來連接塊和塊的子元素
--  Two dash:雙減號用來描述一個塊或者塊的子元素的一種狀態

type-block__element--modifier

區塊(block)

一個區塊是設計或佈局的一部分,它有具體且唯一地意義 ,要麼是語義上的要麼是視覺上的。

在大多數情況下,任何獨立的頁面元素(或複雜或簡單)都可以被視作一個區塊。它的HTML容器會有一個唯一的CSS類名,也就是這個區塊的名字。

針對塊的CSS類名會加一些前綴( ui-),這些前綴在CSS中有類似 name space 的作用。

一個區塊的定義有下面三個基本原則:

  1. CSS中只能使用類名(不能是ID)。
  2. 每一個區塊名應該有一個命名空間(前綴)
  3. 每一條CSS規則必須屬於一個區塊。

例如:一個自定義列表 .product 是一個區塊,通常自定義列表是算在 mod 類別的,在這種情況下,一個 product 列表的block寫法應該為:

.product 

元素(element)

塊中的子元素是塊的子元素,並且子元素的子元素在 BEM 里也被認為是塊的直接子元素。一個塊中元素的類名必須用父級塊的名稱作為前綴。

如上面的例子,li.item 是列表的一個子元素,

.list{}
.list .item{}


.list{}
.list__item{}

這裡可以使用偽嵌套寫成

.list {
    &__item {}
}

修飾符(modifier)

一個「修飾符」可以理解為一個塊的特定狀態,標識著它持有一個特定的屬性。

用一個例子來解釋最好不過了。一個表示按鈕的塊默認有三個大小:小,中,大。為了避免創建三個不同的塊,最好是在塊上加修飾符。這個修飾符應該有個名字(比如:size )和值( smallnormal 或者 big )。

如上面的例子中,表示一個選中的列表,和一個激活的列表項

原本的寫法

.list {}
.list.select {}
.list .item {}
.list .item.active {}
    
用 BEM 的寫法

.list {}
.list--select {}
.list__item {}
.list__item--active {}

用偽嵌套優化之後為

.list {
  &--select {}
  &__item {
    &--active {}
  }
}

使用偽嵌套

使用 & 符號進行偽嵌套

.product {}
.product__item {}

等同於

.product {
    &__item {}
}

嵌套不得大於兩層

原則以 B + E + M 完成,不得使用 B + E + E + M,或是 B + B + E + M 之類的寫法

兩層是指從 sass compiler 後的 CSS 不得有超過兩層階層

.product {
  &__item {
    &--selected {}
  }
}

上面的 SASS 寫法這樣其實也才一層而已哦,因為 compiler 出來之後是

.product {}
.product__item {}
.product__item--selected {}

適當的使用 >

.list {
  &__item > a {}
}

這樣寫只會在 list__item 下一階層的第一個 a tag 會有效果而已,如果在這底下有兩個 a tag ,第二個會失效,這是特別要注意的點。

不要使用 Tag selector

BEM是不允許用 Tag selector 的

.menu li 能搞定的事情需要每個 li 都寫 .menu-item

優點: 就是避免 li 裡的 li 受影響 舉個例子,商品詳情頁是允許商家自定義標籤的,那麼商家展示區域標籤的祖先元素一旦用標籤選擇器定義了樣式,子子孫孫都要背負.

所以十分贊同在無法百分百確定不會嵌套同樣標籤的情況下不用 Tag selector

BEM 解決問題

組件之間的完全解耦,不會造成命名空間的污染,如: .mod-xxx ul li 的寫法帶來的潛在的嵌套風險。

性能

BEM 命名會使得 Class 類名變長,但經過 gzip 壓縮後這個帶寬開銷可以忽略不計

延伸閱讀 - 常用的CSS命名規則

  • 頭:header
  • 內容:content/container
  • 尾:footer
  • 導航:nav
  • 側欄:sidebar
  • 欄目:column
  • 頁面外圍控制整體佈局寬度:wrapper
  • 左右中:left right center
  • 登錄條:loginbar
  • 標誌:logo
  • 廣告:banner
  • 頁面主體:main
  • 熱點:hot
  • 新聞:news
  • 下載:download
  • 子導航:subnav
  • 菜單:menu
  • 子菜單:submenu
  • 搜索:search
  • 友情鏈接:friendlink
  • 頁腳:footer
  • 版權:copyright
  • 滾動:scroll
  • 內容:content
  • 標籤:tags
  • 文章列表:list
  • 提示信息:msg
  • 小技巧:tips
  • 欄目標題:title
  • 加入:joinus
  • 指南:guide
  • 服務:service
  • 註冊:regsiter
  • 狀態:status
  • 投票:vote
  • 合作夥伴:partner

注釋的寫法:

/* Header */
內容區
/* End Header */

Id的命名:

頁面結構

  • 容器: container
  • 頁頭:header
  • 內容:content/container
  • 頁面主體:main
  • 頁尾:footer
  • 導航:nav
  • 側欄:sidebar
  • 欄目:column
  • 頁面外圍控制整體佈局寬度:wrapper
  • 左右中:left right center

導航

  • 導航:nav
  • 主導航:mainnav
  • 子導航:subnav
  • 頂導航:topnav
  • 邊導航:sidebar
  • 左導航:leftsidebar
  • 右導航:rightsidebar
  • 菜單:menu
  • 子菜單:submenu
  • 標題: title
  • 摘要: summary

功能

  • 標誌:logo
  • 廣告:banner
  • 登陸:login
  • 登錄條:loginbar
  • 註冊:register
  • 搜索:search
  • 功能區:shop
  • 標題:title
  • 加入:joinus
  • 狀態:status
  • 按鈕:btn
  • 滾動:scroll
  • 標籤頁:tab
  • 文章列表:list
  • 提示信息:msg
  • 當前的: current
  • 小技巧:tips
  • 圖標: icon
  • 注釋:note
  • 指南:guild
  • 服務:service
  • 熱點:hot
  • 新聞:news
  • 下載:download
  • 投票:vote
  • 合作夥伴:partner
  • 友情鏈接:link
  • 版權:copyright

注意事項::

  1. 一律小寫;
  2. 盡量用英文;
  3. 盡量不縮寫,除非一看就明白的單詞。

CSS樣式表文件命名

  • 主要的 master.css
  • 模塊 module.css
  • 基本共用 base.css
  • 佈局、版面 layout.css
  • 主題 themes.css
  • 專欄 columns.css
  • 文字 font.css
  • 表單 forms.css
  • 補丁 mend.css
  • 打印 print.css
comments powered by Disqus