CSS編寫策略之BEM

項目開發(fā)過程中,一套合適的開發(fā)風(fēng)格指南能夠有效提高實際開發(fā)速度,降低維護(hù)成本。然而在有些項目開發(fā)過程中,CSS并沒有完善的結(jié)構(gòu)或者遵循命名約定,這導(dǎo)致在項目迭代的過程中,CSS結(jié)構(gòu)變得越來越冗余,既降低了開發(fā)效率也影響性能。

現(xiàn)有的CSS編寫策略有很多,如OOCSS,SMACSS,SUIT CSS等等,今天我們要介紹的其中一種——BEM。

什么是BEM

BEM是Block,Element,Modifier的首字母縮寫。是一種CSS的命名規(guī)范。定義了CSS中class的命名規(guī)則,如.b-blockname__element_name--modifier-name。其中以b-開頭的原因稍后會解釋。

Block 代表一個完整獨立的實體

試想一下js中的組件,我們將一種特定可復(fù)用的結(jié)構(gòu)封裝成組件,然后我們可以在任何需要的地方使用該組件標(biāo)簽占位,然后就能將一大段復(fù)雜結(jié)構(gòu)應(yīng)用到該地方。

BEM中的block也是類似的原理,Design中的某些設(shè)計元素可以被用在多個地方,就可以把這個設(shè)計元素的樣式提取成一個獨立的塊,而這個塊的名字就是.b-blockname__element-name--modifier-nameblockname的部分。對于class命名來說,這個block就相當(dāng)于命名空間。

舉個例子:


//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>

彈窗可以作為網(wǎng)頁設(shè)計中一個獨立元素,所以我們可以把獨屬于它的樣式單獨提出來封裝到一個css樣式塊,這個塊的class命名中blockname的部分就是popup。

Element 代表Block里的局部元素

Element指代存在于某個特定block塊內(nèi)部的元素,它可以是block中任意的某個DOM節(jié)點。以上面popup的代碼為例,h1就是一個element,而我們在給它的class命名中以b-popup-modal__title中的__title來表示BEM規(guī)則中E的部分。

Modifiers標(biāo)示了同一個Blcok/Element不同狀態(tài)下的不同樣式

Modifier可以概括為一種狀態(tài)標(biāo)志,對于同一個Block/Element可能有一種基礎(chǔ)樣式,但是在不同的狀態(tài)下會呈現(xiàn)出另一種樣式,這種所謂的狀態(tài)就可以通過命名modifier來區(qū)分。以上面代碼中的.b-btn--disable為例,--disable就是一個modifier,同樣的--primary, --default也是一種modifier。通過定義這樣不同的modifier,我們可以很容易估計某個元素會有什么樣式或者處于什么狀態(tài)。

需要注意的是,所以我們可以單獨定義一個block作為class,但element和modifier都是和block綁定的非獨立模塊,block是他們的命名空間,所以element/modifier一定是和block綁定出現(xiàn)的。

使用BEM編寫CSS

在了解了BEM的基本原理后,接下來再具體說一下它的實現(xiàn)方法。上面已經(jīng)說到BEM實際上是一種命名規(guī)范,在css里就是指class的命名規(guī)范。具體實現(xiàn)規(guī)則團(tuán)隊可以根據(jù)自己的需求做些微調(diào),但原理都離不開block,element和modifier三部分。以下提供一種通用規(guī)則作為參考:

  • Block,element和modifier名字可以包含字母,數(shù)字,下劃線(_)和短橫杠(-),其中-可以作為單詞分隔符代替駝峰式命名方式(不采用駝峰式命名的原因是這里html中大小寫不敏感)。

  • Block的命名可以以b-開頭,因為一個網(wǎng)頁中不是所有的元素都需要被定義成block,b-開頭可以區(qū)分block和普通css class的區(qū)別。例如上面提到的.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

說了這么多之后,最核心的問題還是為什么要使用BEM,它有什么好?

  • 更語意化,可讀性更強

    通過雙下劃線(__), 雙橫杠(--) 等符號代碼維護(hù)者可以輕松理解每一部分的意義,更強的可讀性往往意味著更低的維護(hù)成本。

  • 模塊化,減少層疊帶來的樣式覆蓋的問題

    Block是完全獨立的存在,其內(nèi)部的element/modifier的樣式都在這個block的命名空間下書寫的,所以不會收到其他外部樣式的影響,不存在樣式覆蓋的問題。

    
      .b-popup-modal {
        //...
      }
      .b-popup-modal__title {
        //...
      }
      
    

    以上面代碼為例,無論是block本身或者block內(nèi)部element/modifier,都是針對單個class寫樣式,不需要使用復(fù)雜的css選擇器(.b-popup-modal > .b-popup-modal__title),最大程度地避免了權(quán)重計算。去除掉繼承關(guān)系,css權(quán)重的影響,以block來分的模塊化反而體現(xiàn)得更明顯。

  • 增強樣式的重用性

    就像js組合不同的組件得到更復(fù)雜的組件一樣,我們也可以通過組合不同的block得到更復(fù)雜的樣式,例如使用.b-btn, .b-input來組合一個簡單的form樣式,從而提高代碼的可復(fù)用性,從另一方面講也是降低了維護(hù)成本。

  • 更容易做項目遷移

    因為block樣式是相對獨立的,如果在其他項目有需要,我們完全可以講某個單獨的block相關(guān)的樣式應(yīng)用到其他項目中。

寫在最后

綜上所訴BEM的特點和用法,通過遵循這樣一種命名規(guī)范確實能夠幫助項目維護(hù)一套更易懂,維護(hù)成本相對更低,更容易擴展的CSS代碼庫。

但是一個項目里不是所有的樣式都要做成block。相比于BEM的用法,個人覺得更難的其實是如何精確劃分好每一個block以及對各種modifier的準(zhǔn)確定義。

參考資料
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

友情鏈接更多精彩內(nèi)容