CSS代碼規(guī)范--BEM

BEM

基于組件方式的web開發(fā)方法,基本思想是將用戶界面分成獨(dú)立的模塊。

Block(塊)

通常指模塊,組件

Block 是一個(gè)邏輯上和功能上獨(dú)立的頁(yè)面組件,等同于網(wǎng)頁(yè)組件中的部件(等同于網(wǎng)頁(yè)中的組件)。Block 封裝了行為(Javascript)、模板、樣式(CSS)和其他實(shí)現(xiàn)技術(shù)。獨(dú)立狀態(tài)的 Block 可供復(fù)用,并且促進(jìn)項(xiàng)目開發(fā)和維護(hù)。

內(nèi)容

  • 模塊名稱:描述了它的目的(“它是什么?” —— 菜單或者按鈕),而不是它的狀態(tài)(“它看起來是什么樣子?” —— 紅色或者大的)。
  • 模塊不應(yīng)該影響它所在的環(huán)境,這意味著你不應(yīng)該為模塊設(shè)置會(huì)影響到外部的形狀(影響大小的 padding 或邊框)和定位
  • 你也不應(yīng)該在使用 BEM 的時(shí)候使用 CSS 標(biāo)簽選擇器和 ID 選擇器

使用

嵌套關(guān)系

  • 模塊與模塊之間可以彼此嵌套
  • 你可以有任意級(jí)別的嵌套層次
<!-- 'head' 模塊 -->
<header class="header">
    <!-- 嵌套 'logo' 模塊 -->
    <div class="logo"></div>

    <!-- 嵌套 'search-form' 模塊 -->
    <form class="search-form"></form>
</header>

特點(diǎn)

1、嵌套式的構(gòu)造

Block 可以被嵌套到任何其他 block 里面去。例如,一個(gè)頭部 block 可以包含一個(gè) logo、一個(gè)搜索表單和一個(gè)登錄 block。

image

2、隨意放置

Block 可以在一個(gè)頁(yè)面內(nèi)任意移動(dòng),也可以在頁(yè)面之間或項(xiàng)目之間移動(dòng)。Block 作為獨(dú)立的實(shí)體來實(shí)現(xiàn),這使得在頁(yè)面上改變 block 的位置 并確保其功能和外觀一切正常 成為可能。

image
image

3、可復(fù)用

一個(gè)界面可以包含同一個(gè) block 的幾個(gè)實(shí)例。

image

Element(元素)

內(nèi)容

<h2 id="element">元素</h2>

元素(Element)是一個(gè)模塊(block)的組成部分,且不能脫離模塊單獨(dú)地被使用。例如,一個(gè)菜單項(xiàng)(a menu item )不會(huì)在一個(gè)菜單塊(a menu block )范圍之外使用,因此它是一個(gè)元素(element)。

image
  • 元素名稱:描述了它的目的(用處)(“這是什么?” —— item,text,等等。),而不是它的狀態(tài)(“什么類型的,或者它看起來是什么樣的?” —— 紅色,大的,等等。)
  • 完整的元素名的結(jié)構(gòu)是 block-name__element-name。元素的名字與模塊的名字使用雙下劃線分隔(__)

使用

1、嵌套關(guān)系

  • 元素之間可以彼此嵌套
  • 你可以擁有任意層次的嵌套級(jí)別
  • 一個(gè)元素總是一個(gè)模塊的一部分,而不是另一個(gè)元素的一部分,這意味著元素的名稱不能被定義為 block__elem1__elem2 這樣的層次結(jié)構(gòu)。
<!--
     正確的。完整的元素名的結(jié)構(gòu)符合如下模式:
     'block-name__element-name'
 -->
<form class="search-form">
    <div class="search-form__content">
        <input class="search-form__input"/>
        <button class="search-form__button"></button>
    </div>
</form>

 <!--
     不正確的。完整的元素名的結(jié)構(gòu)不符合如下模式:
     'block-name__element-name'
 -->
<form class="search-form">
    <div class="search-form__content">
        <!-- 推薦:'search-form__input' 或者 'search-form__content-input' -->
        <input class="search-form__content__input"/>
        <!-- 推薦:'search-form__button' 或者 'search-form__content-button' -->
        <button class="search-form__content__button"></button>
    </div>
</form>

如果在模塊名稱上定義了命名空間,也要保證元素名稱是依賴于模塊的(block_elem)。
在 DOM 樹中,一個(gè)模塊可以有元素嵌套結(jié)構(gòu):

<div class="block">
    <div class="block_elem1">
        <div class="block_elem2">
            <div class="block_elem3"></div>
        </div>
    </div>
</div>

在 BEM 的方法論中,這樣的模塊結(jié)構(gòu)通常表示為一個(gè)并列的元素列表:

.block {}
.block_elem1 {}
.block_elem2 {}
.block_elem3 {}

你可以在不改變每個(gè)單獨(dú)的元素的情況下改變一個(gè)模塊的 DOM 結(jié)構(gòu):

<div class="block">
    <div class="block_elem1">
        <div class="block_elem1"></div>
    </div>
    <div class="block_elem3"></div>
</div>

2、組成部分
一個(gè)元素總是一個(gè)模塊的一部分,不可以單獨(dú)使用

<!-- 正確的。元素都位于 'search-form' 模塊內(nèi) -->
<!-- 'search-form' 模塊 -->
<form class="search-form">
    <!-- 在 'search-form' 模塊內(nèi)的 'input' 元素 -->
    <input class="search-form__input" />
    <!-- 在 'search-form' 模塊內(nèi)的 'button' 元素 -->
    <button class="search-form__button"></button>
</form>

<!-- 不正確的。元素位于 'search-form' 模塊的上下文之外 -->
<!-- 'search-form' 模塊 -->
<form class=""search-block>
</form>

<!-- 在 'search-form' 模塊內(nèi)的 'input' 元素 -->
<input class="search-form__input"/>

<!-- 在 'search-form' 模塊內(nèi)的 'button' 元素 -->
<button class="search-form__button"></button>

3、可選性
一個(gè)元素是一個(gè)可選的模塊組件。并不是所有的模塊都必須有元素。

<!-- 'search-form' 模塊 -->
<div class="search-form">
    <!-- 'input' 模塊 -->
    <input class="input"/>

    <!-- 'button' 模塊 -->
    <button class="button"></button>
</div>

①如果這段代碼可能被重用,并且它不依賴于頁(yè)面上的其他組件,那你應(yīng)該創(chuàng)建一個(gè)模塊。

②如果這段代碼在沒有父實(shí)體(模塊)的情況下不能使用,那你應(yīng)該創(chuàng)建一個(gè)元素。

③為了簡(jiǎn)化開發(fā),元素應(yīng)該被分割成一小部分-子元素。在 BEM 方法論中,你不能創(chuàng)建元素的元素,在這種情況下,你需要?jiǎng)?chuàng)建一個(gè)服務(wù)模塊,而不是創(chuàng)建一個(gè)元素。

Modifier(修飾符)

Modifier 是一個(gè) BEM 實(shí)體,它定義了一個(gè) block 或 element 的外觀和行為。
Modifier 可用也可不用(即不一定要用到 modifier)。
Modifier 本質(zhì)上與 HTML 的屬性很相似。同一個(gè) block 會(huì)因?yàn)?modifier 的使用而 看起來與之前有所不同。
例如,菜單塊(the menu block )的外觀可能會(huì)因?yàn)樵谒砩嫌昧艘粋€(gè) modifier 而改變。

內(nèi)容

一種用于定義模塊和元素的外觀,狀態(tài)和行為的實(shí)體。

  • 修飾符的名稱:描述了它的外觀(“多大?”或者“它的主題是什么?”等等—— size_s 或者 theme_islands),它的狀態(tài)(“它與其他有什么不同?” —— disabled,focused,等等)以及他的行為(“它的行為什么?”或者“它如何響應(yīng)用戶?”——比如 directions_left-top)。
  • 修飾符的名字與模塊或者元素的名字使用單下劃線分隔(_)

修飾符的類型

1、Boolean

  • 當(dāng)修飾符的存在或不存在是重要的,與它的值無(wú)關(guān)時(shí)使用這種類型的修飾符。比如:disabled。如果一個(gè)布爾類型的修飾符是可見的,它的值被假定為 true。
  • 修飾符的全名的結(jié)構(gòu)遵循如下模式:
  • Modifier(修飾符 )

block-name_modifier_name

block-name__element-name_modifier-name

<!-- 'search-form' 模塊有一個(gè) ‘focused’ 的布爾類型的修飾符 -->
<form class="search-form search-form_focused">
    <input class="search-form__input"/>

    <!-- 'button' 元素有一個(gè) 'disabled' 的布爾類型修飾符 -->
    <button class="search-form__button search-form__button_disabled">Search</button>
</form>

2、鍵-值

  • 當(dāng)修飾符的值是重要的使用鍵值對(duì)類型。

“一個(gè) islands 設(shè)計(jì)主題的按鈕”:menu_theme_islands

  • 這種類型的修飾符的全名的結(jié)構(gòu)遵循如下模式:

block-name_modifier-name_modifier-value

block-name__element-name_modifier-name_modifier-value

<!-- The `search-form` 模塊有值為 'islands' 的 `theme` 修飾 -->
<form class="search-form search-form_theme_islands">
    <input class="search-form__input">

    <!-- The `button` 元素有值為 'm' 的 `size` 修飾 -->
    <button class="search-form__button search-form__button_size_m">Search</button>
</form>

<!-- 你不能同時(shí)使用兩個(gè)具有不同值的的相同修飾符 -->
<form class="search-form
             search-form_theme_islands
             search-form_theme_lite">

    <input class="search-form__input">

    <button class="search-form__button
                   search-form__button_size_s
                   search-form__button_size_m">
        Search
    </button>
</form>

使用

一個(gè)修飾符不能被單獨(dú)使用。

  • 從 BEM 的角度,一個(gè)修飾符不能脫離模塊或元素而被使用。一個(gè)修飾符應(yīng)該改變實(shí)體的外觀,行為或者狀態(tài),而不是替換它。
<!-- 正確的。'search-form' 模塊有值為 'islands' 的 'theme' 修飾符 -->
<form class="search-form search-form_theme_islands">
    <input class="search-form__input">

    <button class="search-form__button">Search</button>
</form>

<!-- 不正確的。'search-form' 丟失了 -->
<form class="search-form_theme_islands">
    <input class="search-form__input">

    <button class="search-form__button">Search</button>
</form>

混合模式:一種在單一的 DOM 節(jié)點(diǎn)上使用不同 BEM 實(shí)體的技術(shù)

混合模式允許

  • 結(jié)合多個(gè)實(shí)體的行為和樣式,而不是重復(fù)編寫代碼
  • 在現(xiàn)有代碼的基礎(chǔ)上創(chuàng)建具有新語(yǔ)義的UI組件
<!-- 'header' 模塊 -->
<div class="header">
    <!--
        將 'header' 模塊的 'search-form' 元素與 'search-form' 模塊混合在一起使用
    -->
    <div class="search-form header__search-form"></div>
</div>

在這個(gè)例子中,我們將 header 模塊的 search-form 元素與 search-form 模塊的行為和樣式結(jié)合在一起。這種方式允許我們?cè)?header__search-form 元素上設(shè)置額外的形狀和定位,而 search-form 模塊仍然是通用的。因此,我們可以在任何環(huán)境中使用模塊,因?yàn)槟K沒有指定任何填充。這正是我們可以獨(dú)立調(diào)用模塊的原因。

文件系統(tǒng):在 BEM 方法論中采用的組件概念同樣適用于項(xiàng)目的文件結(jié)構(gòu)中。模塊、元素和修飾符的實(shí)現(xiàn)可以被分在獨(dú)立的文件中,這意味著,我們單獨(dú)地使用它們。

  • 一個(gè)單獨(dú)的模塊對(duì)應(yīng)一個(gè)單獨(dú)的目錄
  • 模塊和其對(duì)應(yīng)的目錄擁有相同的名字。比如, header 模塊放置在 header/ 目錄中,menu 模塊放置在 menu/ 目錄中。
  • 一個(gè)模塊的實(shí)現(xiàn)分為單獨(dú)的文件。比如, header.cssheader.js。
  • 模塊目錄是其元素和修飾所在目錄的根目錄。
  • 元素目錄的名稱以雙下劃線(__)開始。比如,header/__logo/menu/__item。
  • 修飾目錄的名稱以單下劃線(_)開始。比如,header_fixedmenu/_theme_islands/
  • 元素和修飾的實(shí)現(xiàn)分為不同的文件。比如,header__input.jsheader_theme_islands.css。
search-form/                           # Directory of the search-form

    __input/                           # Subdirectory of the search-form__input
        search-form__input.css         # CSS implementation of the
                                       # search-form__input element
        search-form__input.js          # JavaScript implementation of the
                                       # search-form__input element

    __button/                          # Subdirectory of the search-form__button element
        search-form__button.css
        search-form__button.js

    _theme/                            # Subdirectory of the search-form_theme modifier
        search-form_theme_islands.css  # CSS implementation of the search-form block
                                       # that has the theme modifier with the value
                                       # islands
        search-form_theme_lite.css     # CSS implementation of the search-form block
                                       # that has the theme modifier with the value
                                       # lite

search-form.css                        # CSS implementation of the search-form block
search-form.js                         # JavaScript implementation of the
                                       # search-form block

這樣的文件結(jié)構(gòu)可以很好地支持我們重用代碼。

BEM entity(BEM 實(shí)體)

Block,element 和 modifier 合起來就被成為 BEM entity。它是一個(gè) 既可以用來指代單獨(dú)的 BEM 實(shí)體又可以作為 block、element 和 modifier 的總稱的 概念。

Mix(混合體)

Mix 是被托管在(being hosted on)一個(gè)單獨(dú)的 DOM 節(jié)點(diǎn)上的 不同 BEM 實(shí)體(混合而成)的一個(gè)實(shí)例。

Mix允許我們

  • 把幾個(gè) BEM 實(shí)體的功能(behavior)和樣式 組合在一起,同時(shí)避免重復(fù)代碼
  • 在現(xiàn)有的 BEM 實(shí)體的基礎(chǔ)上 創(chuàng)建語(yǔ)義上的新界面組件。讓我們想一下這種 mix 情形:把一個(gè) block 與 另一個(gè) block 的一個(gè) element 組合在一起。

我們假設(shè),項(xiàng)目里的鏈接(links)通過一個(gè)鏈接塊(a link block)來實(shí)現(xiàn)。我們需要把菜單項(xiàng)(menu items )格式化成鏈接(links)。這里有幾種實(shí)現(xiàn)方法:

  • 創(chuàng)建一個(gè) 可以把菜單項(xiàng)(item)轉(zhuǎn)變成鏈接(link)的 modifier。實(shí)現(xiàn)這樣一個(gè) modifier 即必然牽涉到 復(fù)制鏈接塊的功能和樣式。這樣一來就會(huì)導(dǎo)致代碼重復(fù)。
  • 取一個(gè) 把一個(gè)通用的鏈接塊(link block )與一個(gè)菜單塊的一個(gè)鏈接元素(a link element ) 組合在一起的 mix。兩個(gè) BEM 實(shí)體的混合體(mix)可以讓我們不用復(fù)制代碼,就可以使用鏈接塊的基本鏈接功能 和 菜單塊的 CSS 規(guī)則。

BEM tree(BEM 樹 )

BEM tree 是網(wǎng)頁(yè)結(jié)構(gòu)在 block、element 和 modifier 方面的表示(representation)。這是一個(gè)在 DOM 樹之上的抽象概念,它描述了 BEM 實(shí)體的名稱、它們的狀態(tài)、順序、嵌套和輔助數(shù)據(jù)。在現(xiàn)實(shí)生活中的項(xiàng)目,BEM tree可以呈現(xiàn)在任何支持樹結(jié)構(gòu)的形式(format)中。

一個(gè)DOM樹

<header class="header">
<img class="logo">
<form class="search-form">
<input type="input">
<button type="button"></button>
</form>
<div class="lang-switcher"></div>
</header>

BEM tree

header
    ├──logo
    └──search-form
        ├──input
        └──button
    └──lang-switcher

在 XML 和 BEMJSON 格式中,該 BEM tree 則是這樣的
XML

<block:header>
    <block:logo/>
    <block:search-form>
        <block:input/>
        <block:button/>
    </block:search-form>
    <block:lang-switcher/>
</block:header>

BEMJSON

{
    block: 'header',
    content : [
        { block : 'logo' },
        {
            block : 'search-form',
            content : [
                { block : 'input' },
                { block : 'button' }
            ]
        },
        { block : 'lang-switcher' }
    ]
}

Block implementation(BEM實(shí)現(xiàn) )

Block implementation 是指一組各不相同的 技術(shù),這些技術(shù)決定著 BEM 實(shí)體以下幾方面:

  • 行為/功能(behavior)
  • 外觀
  • 測(cè)試
  • 模板
  • 文檔(documentation)
  • 依賴描述
  • 附加數(shù)據(jù)(例如:圖片)

Implementation technology(實(shí)現(xiàn)技術(shù))

Implementation technology 是一種用于實(shí)現(xiàn)一個(gè) block 的技術(shù)。Block 可以用一種或多種技術(shù)來實(shí)現(xiàn),例如:

  • 行為/功能(behavior)-- JavaScript, CoffeeScript
  • 外觀-- CSS, Stylus, Sass
  • 模板-- BEMHTML, BH, Jade, Handlebars, XSL
  • 文檔(documentation)-- Markdown, Wiki, XML

例如,如果一個(gè) block 的外觀是用 CSS 來定義的,這意味著 block 是用 CSS 技術(shù)實(shí)現(xiàn)的。同樣地,如果一個(gè) block 的文檔是用 Markdown 格式寫的,block 就是用 Markdown 技術(shù)來實(shí)現(xiàn)的。

Block redefinition(塊重定義)

Block implementation 是指通過在不同的層級(jí)上增加新的功能到 block 來修改 block。

Redifinition level(重定義等級(jí))

Redefinition level 是指一組 BEM 實(shí)體和它們的部分實(shí)現(xiàn)。

一個(gè) block 的最終實(shí)現(xiàn) 可以被分成 不同的重定義層級(jí)。每一個(gè)新的層級(jí)都會(huì)擴(kuò)展或覆蓋原始的 block implementation。最終的結(jié)果由 來自所有按照預(yù)設(shè)的連續(xù)的順序排列的重定義層級(jí)的獨(dú)立的 block implementation technologies 組合而成。
任何 BEM 的實(shí)現(xiàn)技術(shù)都可以被重新定義。

例如,有一個(gè)連接到項(xiàng)目的第三方庫(kù)。這個(gè)庫(kù)包含現(xiàn)成的 block implementation。該項(xiàng)目指定的 block 保存在一個(gè)另一個(gè)重定義層級(jí)。比方說,我們需要修改這個(gè)庫(kù)里的某一個(gè) block 的外觀。這并不需要在庫(kù)的源代碼里修改 block 的 CSS 規(guī)則 或者 在項(xiàng)目里復(fù)制代碼。我們只需在項(xiàng)目里為 那一個(gè) block 創(chuàng)建額外的 CSS 規(guī)則。在生成過程中,最終實(shí)現(xiàn)將會(huì)結(jié)合庫(kù)級(jí)別的原有規(guī)則和項(xiàng)目級(jí)別中新的樣式規(guī)則。

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

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