轉載必須標明出處,謝謝。文章有疏漏淺薄之處,歡迎各位大神指正css
項目開發過程當中,一套合適的開發風格指南可以有效提升實際開發速度,下降維護成本。然而在有些項目開發過程當中,CSS並無完善的結構或者遵循命名約定,這致使在項目迭代的過程當中,CSS結構變得愈來愈冗餘,既下降了開發效率也影響性能。html
現有的CSS編寫策略有不少,如OOCSS,SMACSS,SUIT CSS等等,今天咱們要介紹的其中一種——BEM。bash
BEM是Block,Element,Modifier的首字母縮寫。是一種CSS的命名規範。定義了CSS中class的命名規則,如.b-blockname__element_name--modifier-name
。其中以b-
開頭的緣由稍後會解釋。模塊化
試想一下js中的組件,咱們將一種特定可複用的結構封裝成組件,而後咱們能夠在任何須要的地方使用該組件標籤佔位,而後就能將一大段複雜結構應用到該地方。性能
BEM中的block也是相似的原理,Design中的某些設計元素能夠被用在多個地方,就能夠把這個設計元素的樣式提取成一個獨立的塊,而這個塊的名字就是.b-blockname__element-name--modifier-name
中blockname
的部分。對於class命名來講,這個block就至關於命名空間。spa
舉個例子:設計
//html
<div class="b-popup-modal">
<h1 class="b-popup-modal__title">title</h1>
<div class="b-popup-modal__body">
body content
</div>
<div class="b-popup-modal__footer">
<button class="b-btn b-btn--primary b-btn--disable">Submit</button>
<button class="b-btn b-btn--default">Cancel</button>
</div>
</div>
複製代碼
彈窗能夠做爲網頁設計中一個獨立元素,因此咱們能夠把獨屬於它的樣式單獨提出來封裝到一個css樣式塊,這個塊的class命名中blockname的部分就是popup
。code
Element指代存在於某個特定block塊內部的元素,它能夠是block中任意的某個DOM節點。以上面popup的代碼爲例,h1
就是一個element,而咱們在給它的class命名中以b-popup-modal__title
中的__title
來表示BEM規則中E的部分。orm
Modifier能夠歸納爲一種狀態標誌,對於同一個Block/Element可能有一種基礎樣式,可是在不一樣的狀態下會呈現出另外一種樣式,這種所謂的狀態就能夠經過命名modifier來區分。以上面代碼中的.b-btn--disable
爲例,--disable
就是一個modifier,一樣的--primary
, --default
也是一種modifier。經過定義這樣不一樣的modifier,咱們能夠很容易估計某個元素會有什麼樣式或者處於什麼狀態。htm
須要注意的是,因此咱們能夠單獨定義一個block做爲class,但element和modifier都是和block綁定的非獨立模塊,block是他們的命名空間,因此element/modifier必定是和block綁定出現的。
在瞭解了BEM的基本原理後,接下來再具體說一下它的實現方法。上面已經說到BEM其實是一種命名規範,在css裏就是指class的命名規範。具體實現規則團隊能夠根據本身的需求作些微調,但原理都離不開block,element和modifier三部分。如下提供一種通用規則做爲參考:
Block,element和modifier名字能夠包含字母,數字,下劃線(_)和短橫槓(-),其中-
能夠做爲單詞分隔符代替駝峯式命名方式(不採用駝峯式命名的緣由是這裏html中大小寫不敏感)。
Block的命名能夠以b-
開頭,由於一個網頁中不是全部的元素都須要被定義成block,b-
開頭能夠區分block和普通css class的區別。例如上面提到的.b-popup-modal
, .b-btn
。
用雙下劃線(__)來指示接下來是一個element名字,例如上面b-popup-modal__title
中的__title
。一樣的還有__body
, __footer
。
經過雙短橫槓(--)來指示modifier的名字。
不是每個Block/Element都須要定義Modifier,這徹底取決於實際需求。
modifier的位置既能夠在block後面,也能夠跟在element後面。例如.b-btn--disable
, .b-nav__nav-item--visited
。
對於跟在block後的modifier,後面也能夠再追加element,如.b-btn--disable__icon
。
說了這麼多以後,最核心的問題仍是爲何要使用BEM,它有什麼好?
更語意化,可讀性更強
經過雙下劃線(__), 雙橫槓(--) 等符號代碼維護者能夠輕鬆理解每一部分的意義,更強的可讀性每每意味着更低的維護成本。
模塊化,減小層疊帶來的樣式覆蓋的問題
Block是徹底獨立的存在,其內部的element/modifier的樣式都在這個block的命名空間下書寫的,因此不會收到其餘外部樣式的影響,不存在樣式覆蓋的問題。
.b-popup-modal {
//...
}
.b-popup-modal__title {
//...
}
複製代碼
以上面代碼爲例,不管是block自己或者block內部element/modifier,都是針對單個class寫樣式,不須要使用複雜的css選擇器(.b-popup-modal > .b-popup-modal__title
),最大程度地避免了權重計算。去除掉繼承關係,css權重的影響,以block來分的模塊化反而體現得更明顯。
加強樣式的重用性
就像js組合不一樣的組件獲得更復雜的組件同樣,咱們也能夠經過組合不一樣的block獲得更復雜的樣式,例如使用.b-btn
, .b-input
來組合一個簡單的form樣式,從而提升代碼的可複用性,從另外一方面講也是下降了維護成本。
更容易作項目遷移
由於block樣式是相對獨立的,若是在其餘項目有須要,咱們徹底能夠講某個單獨的block相關的樣式應用到其餘項目中。
綜上所訴BEM的特色和用法,經過遵循這樣一種命名規範確實可以幫助項目維護一套更易懂,維護成本相對更低,更容易擴展的CSS代碼庫。
可是一個項目裏不是全部的樣式都要作成block。相比於BEM的用法,我的以爲更難的實際上是如何精確劃分好每個block以及對各類modifier的準肯定義。