css的組織方式:BEM規則

why?

無論選擇了什麼樣的css組織方法,你都會從更加結構化的css 和 Ui 結構中獲益。有些方式不那麼嚴格,更加靈活。而另一些方法則更加易於理解,適用於團隊協作。

爲什麼要選擇bem呢?它不像其他語法(smacss)那麼複雜,但是仍然可以提供給我們優良的代碼結構和易於識別的術語。

模塊化

block永遠不依賴於頁面上的其他元素,因此不會遇到級聯問題。而且易於從舊項目中遷移。只要從某一個塊級元素開始即可。

可複用

以不同的方式組合獨立的塊級元素,重用它們,減少可維護的代碼量。甚至可以構造一個基於block的庫。

結構

bem法讓css代碼有良好的組織結構,既簡單,又易於理解。

what?

概念

  • b – block
    一個本身就是有意義的獨立實體。儘管一個block可以和其他block嵌套和共同發揮作用,但語義上所有blocks是平等的,並沒有等級或者優先級之分。沒有表現爲DOM的整體實體(例如控制器或模型)也可以是塊。

    塊名稱可以包含拉丁字母,數字和短劃線。

    任何有class name的dom節點都可以成爲block。

    在一頁中,沒有對其他Blocks、elements的依賴。

    e.g: header, container, menu, checkbox, input

  • e – element
    Block的一部分,沒有獨立的意義,而且在語義上依附於Block存在。
    e.g: menu item, list item, checkbox caption, header title

    元素名稱可以包含拉丁字母,數字,短劃線和下劃線。主要是以兩個下劃線接在block之後,來表示從屬關係。

    在一個block下的任何dom節點都可以是element。

    沒有對同一頁上其他blocks/elements的依賴。

    // 好例子
    .block__elem {
      color: #fff;
    }
    
    //壞例子
    .block .block__elem {
      color: #042;
    }
    div.block__elem {
      color: #042;
    }
    
  • m – modifier
    修飾符,一個block或者element上的flag,體現了外觀或者行爲的變化。

    修飾符名稱可能包含拉丁字母,數字,短劃線和下劃線。以兩個短劃線接在element/block的類名之後,諸如.block--mod, .block__elem--mod.block--color-blackblock--color-red。在複雜修飾符中的空格用短劃線來代替。

    e.g: disabled, highlighted, checked, fixed, size big, bg yellow

    修飾符是您添加到塊/元素DOM節點的額外類名。僅將修飾符類添加到它們修改的塊/元素,並保留原始類名。是添加不是替換

     <!-- 好例子 -->
    <div class="block block--mod">...</div>
      <div class="block block--size-big
      	block--shadow-yes">...</div>
    
    <!-- 壞例子 -->
    <div class="block--mod">...</div>
    

    在block層級的修飾符下的元素,可以這麼寫

    
    .block--mod .block__elem {}
    
    

    例子:

    <form class="form form--theme-xmas form--simple">
      <input class="form__input" type="text" />
      <input
        class="form__submit form__submit--disabled"
        type="submit" />
    </form>
    
    .form { }
    .form--theme-xmas { }
    .form--simple { }
    .form__input { }
    .form__submit { }
    .form__submit--disabled { }
    

例子

http://getbem.com/assets/github_buttons.jpg

如上圖,可以在按鈕上應用任何想要的標籤,如Button,a, div 等,可使用block--modifier-value語法。

.button {
	display: inline-block;
	border-radius: 3px;
	padding: 7px 12px;
	border: 1px solid #D5D5D5;
	background-image: linear-gradient(#EEE, #DDD);
	font: 700 13px/18px Helvetica, arial;
}
.button--state-success {
	color: #FFF;
	background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x;
	border-color: #4A993E;
}
.button--state-danger {
	color: #900;
}

faq:

  1. 爲什麼要選擇bem作爲css模塊化的解決方案?

精髓在於 塊的獨立性。

如果僅談論CSS模塊化解決方案,BEM的關鍵特性是塊的獨立性。 遵循CSS建議可以將塊放入頁面上的任何位置,並確保它不會受到周圍環境的影響。 此外,如果您最近需要將另一個塊嵌套到當前塊中,則可以保證它們完全兼容。 換句話說,在維護Web應用程序時,您可以在頁面中移動塊,添加其他塊並組合它們。

BEM CSS明確地定義了哪個CSS屬於一個界面,因此使用它可以回答諸如“我可以刪除這段代碼嗎?” 和“如果我改變這段代碼,會發生什麼以及哪些接口部分會受到影響?”的問題。

  1. 爲什麼要使用block–modifier,而不是將modifier直接和Block同時作用於一個元素上?

也就是說,爲什麼要避免使用menu__item button active?

    1. 因爲同一個dom節點可以既是Block,又是element,所以需要確認一個修飾符是基於block的還是基於element的。如果寫成<div class="menu__item button active"></div>,就無法區分menu__itme.active還是button.active了。而加上前綴後,button--active則明確地指出了active僅僅影響的是按鈕。
    1. 另一點是CSS的優先級。組合的選擇器比單一的類選擇器優先級更高。寫的時候還要注意計算優先級的問題。但如果使用了前綴式的修飾符,就可以肯定層疊的選擇器會Overwrite 修飾符。(這一點在應用了scoped後不用考慮)。
    1. 結構更加分明。比如<div class="block block--mod">,可以清晰地看到Block的結構。但<div class="block mod">卻不能起到同樣的效果。當全局搜索block--mod時,尤其會感謝這種實踐方式。
  1. 如何命名修飾符?能否直接把它的css作爲依據命名修飾符?

不能。首先,.block__element--border-bottom-5px看上去奇醜無比,其次,在實踐中,如果把5px改成了6px,那麼還要連帶選擇器的名一起改,麻煩。而且,不能保證修飾符會永遠只擁有某一個CSS屬性,而且永遠擁有它。所以,儘量還是選擇語義上有意義的名字來命名修飾符。

  1. 類似block__elem1__elem2__elem3的元素嵌套元素怎麼命名選擇器?

根據BEM方法,塊結構應儘量平整,您需要反映塊的嵌套DOM結構。所以,對元素嵌套元素,可以都攤平到塊級之下的子元素。如:

<div class='block'>
    <div class='block__elem1'>
        <div class='block__elem2'>
            <div class='block__elem3'></div>
            <div class='block__elem4'></div>
        </div>
    </div>
</div>

css結構應該爲:

.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}

這樣,每一個element都只依賴於外層的block,可以很輕鬆地在block內部遷移代碼,如下所示。

<div class='block'>
    <div class='block__elem1'>
        <div class='block__elem2'></div>
    </div>
    <div class='block__elem3'></div>
    <div class='block__elem4'></div>
</div>

【筆者言:】我對這一點有異議。假如block__elem2中是flex佈局子元素elem3, elem4,那麼在遷移在後者時,仍然需要改動其父級元素。建議根據具體情況靈活採用,必要時,可以把內部的element作爲一個block,再進行新的嵌套。

  1. bem不支持全局的css重置嗎?

BEM不會禁止使用css全局reset,但用BEM的方式重置會更有效。

BEM認爲每一個塊都是獨立的,不依賴於global reset css存在,而且global reset通常是以tag作爲選擇器,這也違反了規則。相反,bem建議在每個塊上進行重置。利用Mixin的方式,假設Menu__item 和 list__item都是li元素,則二者都需要引入li的重置代碼。 您可能會擔心具有相同重置規則的多個塊將在結果代碼中重複出現。 但這就是CSS優化器應該爲您做的事情。 作爲開發人員,您可以獨立開發每個塊,就好像同一頁面上沒有其他塊一樣。

.menu {
    @include reset-list;
}
.menu__item {
    @include reset-list-item;
}

/* ... */

.list {
    @include reset-list;
}
.list__item {
    @include reset-list-item;
}

另外,以這樣的方式去reset 全局,還可以避免在引入第三方庫的時候,reset代碼和第三方庫的代碼起了衝突。

【筆者言:】這樣做的壞處是增加了代碼量,需要開發者控制每一個Block的樣式,給每一個都加上mixin。從實踐上來講,我不反對全局加入css reset。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章