BEM 初學者:為什麼需要 BEM

已發表: 2022-03-10
快速總結 ↬ CSS 樣式隔離是 BEM 使用最常見的起點。 但這是 BEM 能給你的最少的東西。 BEM 在您的項目中引入了一種系統方法,並使其遠離混亂。

BEM 使您的代碼可擴展和可重用,從而提高生產力並促進團隊合作。 即使您是團隊中唯一的成員,BEM 也可能對您有用。 然而,許多開發人員認為,像 BEM 這樣的系統方法給他們的項目增加了額外的界限,並使您的項目超載、繁瑣和緩慢。

我們將以濃縮的形式收集 BEM 的所有主要方面。 本文幫助您在短短 20 分鐘內了解 BEM 的基本思想,並摒棄系統方法對您的項目有害的偏見。

Big BEM 由方法技術工具組成。 在本文中,我們將更多地討論方法論本身,因為它是大量開發人員的集中經驗,它為任何項目帶來了系統化的方法。

為了向您展示 BEM 的一些實際案例,我們將涉及 BEM 技術並完全跳過庫和工具。

從理論到實踐:

  • 我們不使用除類之外的任何選擇器的主要原因
  • BEM的基礎知識
    • 塊和元素
    • 修飾符和混合
    • 文件結構中的塊
  • 方法論的非明顯優勢
  • 實際案例:BEM 不僅僅適用於 CSS
  • BEM 是一個可定制的系統

那麼,BEM是英雄還是惡棍? 由你決定! 但首先,請閱讀文章。

BEM 作為蝙蝠俠的標誌
BEM蝙蝠俠
跳躍後更多! 繼續往下看↓

我們不使用除類之外的任何選擇器的主要原因

BEM 方法的基本規則之一是只使用類選擇器。 在本節中,我們將解釋原因。

  • 為什麼我們不使用 ID?
  • 為什麼我們不使用標籤選擇器?
  • 為什麼我們不使用通用選擇器?
  • 為什麼我們不使用 CSS 重置?
  • 為什麼我們不使用嵌套選擇器?
  • 為什麼我們不在選擇器中結合標籤和類呢?
  • 為什麼我們不使用組合選擇器-
  • 為什麼我們不使用屬性選擇器?

我們不使用 ID(ID 選擇器)

ID 為 HTML 元素提供了一個唯一的名稱。 如果名稱是唯一的,則不能在界面中重複使用它。 這可以防止您重用代碼。

常見的誤解

  1. 使用 JavaScript 需要 ID。
    現代瀏覽器可以使用 ID 或類。 任何類型的選擇器在瀏覽器中都以相同的速率進行處理。
  2. ID 與<label>標記一起使用。
    如果將<label>放在控件中,則不需要 ID。 而不是<input id="ID"><label for="ID">Text</label> ,只需使用<label><input type="...">Text</label>

我們不使用標籤選擇器

HTML 頁面標記不穩定:新設計可以更改部分的嵌套、標題級別(例如,從<h1><h3> )或將<p>段落轉換為<div>標記。 任何這些更改都會破壞為標籤編寫的樣式。 即使設計沒有改變,標籤集也是有限的。 要在另一個項目中使用現有佈局,您必須解決為相同標籤編寫的樣式之間的衝突。

一組擴展的語義標籤也不能滿足所有的佈局需求。

例如,當頁眉包含徽標時。 單擊徽標會打開網站的主頁( index )。 您可以使用標籤來標記它,方法是使用圖像的<img>標記和鏈接的<a>標記。

 <header> <a href="/"> <img src="img.logo.png" alt="Logo"> </a> </header>

要區分標誌鏈接和文本中的普通鏈接,您需要額外的樣式。 現在從徽標鏈接中刪除下劃線和藍色:

 header a { ... }

徽標鏈接不需要顯示在主頁上,因此更改索引頁面標記:

 <header> <!-- the <a> tag is replaced with <span> --> <span> <img src="img.logo.png" alt="Logo"> </span> </header>

您不需要刪除<span>標記的下劃線和藍色。 因此,讓我們為來自不同頁面的徽標鏈接製定一般規則:

 header a, header span { ... }

乍一看,這段代碼似乎沒問題,但想像一下如果設計師從佈局中刪除了徽標。 選擇器名稱無法幫助您了解應從帶有徽標的項目中刪除哪些樣式。 “header a”選擇器不顯示鏈接和徽標之間的連接。 該選擇器可以屬於標題菜單中的鏈接,或者,例如,屬於作者個人資料的鏈接。 “標題跨度”選擇器可以屬於標題的任何部分。

為避免混淆,只需使用logo類選擇器來編寫徽標樣式:

 .logo { ... }

我們不使用 CSS 重置

CSS 重置是為整個頁面創建的一組全局 CSS 規則。 這些樣式影響所有的佈局節點,違反了組件的獨立性,並且更難重用它們。

在 BEM 中,“reset”和“normalize”甚至不用於單個塊。 重置和規範化會取消現有樣式並用其他樣式替換它們,無論如何您都必須稍後更改和更新。 結果,開發人員必須編寫樣式來覆蓋剛剛重置的樣式。

我們不使用通用選擇器 ( * )

通用選擇器表示項目具有影響佈局中所有節點的樣式。 這限制了佈局在其他項目中的重用:

  • 您必須另外將帶有星號的樣式轉移到項目中。 但在這種情況下,通用選擇器可能會影響新項目中的樣式。
  • 帶有星號的樣式必須添加到您正在傳輸的佈局中。

此外,通用選擇器可以使項目代碼不可預測。 例如,它會影響通用庫組件的樣式。

常見的樣式並不能節省您的時間。 開發人員通常會從重置組件的所有邊距開始( * { margin: 0; padding: 0; } ),但隨後他們仍然將它們設置為與佈局中的相同(例如, margin: 12px; padding: 30px; )。

我們不使用嵌套選擇器

嵌套選擇器增加了代碼耦合,使代碼難以重用。

BEM 方法不禁止嵌套選擇器,但建議不要過多使用它們。 例如,如果您需要根據塊的狀態或其分配的主題更改元素的樣式,則嵌套是合適的。

 .button_hovered .button__text { text-decoration: underline; } .button_theme_islands .button__text { line-height: 1.5; }

我們不使用組合選擇器

組合選擇器比單個選擇器更具體,這使得重新定義塊更加困難。

考慮以下代碼:

 <button class="button button_theme_islands">...</button>

假設您在.button.button_theme_islands選擇器中設置 CSS 規則以減少編寫工作。 然後將“active”修飾符添加到塊中:

 <button class="button button_theme_islands button_active">...</button>

.button_active選擇器不會重新定義編寫為.button.button_theme_islands的塊屬性,因為.button.button_theme_islands.button_active更具體。 要重新定義它,請將塊修飾符選擇器與.button選擇器結合起來,並在.button.button_theme_islands下方聲明它,因為這兩個選擇器同樣具體:

 .button.button_theme_islands {} .button.button_active {}

如果您使用簡單的類選擇器,則重新定義樣式不會有問題:

 .button_theme_islands {} .button_active {} .button {}

我們不會在選擇器中組合標籤和類

在同一個選擇器中組合標籤和類(例如button.button )使 CSS 規則更加具體,因此更難重新定義它們。

考慮以下代碼:

 <button class="button">...</button>

假設您在button.button選擇器中設置 CSS 規則。 然後將active修飾符添加到塊中:

 <button class="button button_active">...</button>

.button_active選擇器不會重新定義編寫為button.button的塊屬性,因為button.button.button_active更具體。 為了使其更具體,您應該將塊修飾符選擇器與button.button_active標籤結合起來。

隨著項目的發展,您最終可能會得到帶有input.buttonspan.buttona.button選擇器的塊。 在這種情況下, button塊的所有修飾符及其所有嵌套元素都需要針對每個實例進行四種不同的聲明。

可能的例外

在極少數情況下,該方法允許組合標籤和類選擇器。 例如,這可用於在無法生成正確佈局的 CMS 系統中設置評論樣式。

您可以使用註釋來編寫文本、插入圖像或添加標記。 為了使它們與網站設計相匹配,開發人員可以為用戶可用的所有標籤預定義樣式並將它們級聯到嵌套塊:

 <div class="content"> ... <!-- the user's text --> </div> CSS rules: .content a { ... } .content p { font-family: Arial, sans-serif; text-align: center; }

我們不使用屬性選擇器

屬性選擇器比類選擇器提供的信息更少。 作為證明,考慮一個在標題中包含搜索表單的示例:

 <header> <form action="/"> <input name="s"> <input type="submit"> </form> </header>

嘗試使用選擇器屬性來編寫表單樣式:

 header input[type=submit], header input[type=checkbox] { width: auto; margin-right: 20px; } header input[type=checkbox] { margin: 0; }

在此示例中,您無法從選擇器名稱中確定樣式屬於搜索表單。 使用類使其更清晰。 課程沒有限制你寫得很清楚。 例如,你可以這樣寫:

 .form .search { ... }

現在代碼沒有歧義了,很明顯樣式屬於搜索表單。

但是嵌套選擇器仍然使 CSS 規則更加具體,並阻止您在項目之間轉移佈局。 要擺脫嵌套,請使用 BEM 原則。

總結class是唯一可以讓你隔離項目中各個組件的樣式的選擇器; 增加代碼的可讀性並且不限制佈局的重用。

CSS 樣式隔離是 BEM 旅程最常見的起點。 但這是 BEM 能給你的最少的東西。 要了解 BEM 中孤立的獨立組件是如何排列的,您需要學習基本概念,即塊、元素、修飾符和混合。 讓我們在下一節中執行此操作。

BEM的基礎知識

  • 塊和元素
  • 修飾符和混合
  • 文件結構中的塊

塊和元素

BEM 方法是一組通用規則,無論使用何種技術,例如 CSS、Sass、HTML、JavaScript 或 React,都可以應用這些規則。

BEM 有助於解決以下任務:

  • 重用佈局;
  • 在項目中安全地移動佈局片段;
  • 在項目之間移動完成的佈局;
  • 創建穩定、可預測和清晰的代碼;
  • 減少項目調試時間。

在 BEM 項目中,界面由可以包含元素的塊組成。 塊是頁面的獨立組件。 元素不能存在於塊之外,因此請記住每個元素只能屬於一個塊。

BEM 中的前兩個字母代表B鎖和元素。 塊名稱始終是唯一的。 它為元素設置命名空間並提供塊部件之間的可見連接。 塊名稱很長但清晰,以便顯示組件之間的連接並避免在傳輸佈局時丟失這些組件的任何部分。

要了解 BEM 命名的全部功能,請考慮這個帶有表單的示例。 根據 BEM 方法,表單是使用form塊實現的。 在 HTML 中,塊名稱包含在class屬性中:

 <form class="form" action="/">

表單中沒有意義的所有部分( form塊)都被視為其元素。 所以搜索框( search )和按鈕( submit )是form塊的元素。 類還表明一個元素屬於該塊:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

請注意,塊的名稱與元素的名稱使用特殊的分隔符分隔。 在 BEM 經典命名方案中,使用兩個下劃線作為分隔符。 任何東西都可以作為分隔符。 還有其他命名約定,每個開發人員都會選擇適合他們的命名約定。 重要的是分隔符允許您以編程方式將塊與元素和修飾符區分開來。

選擇器名稱清楚地表明,為了將表單移動到另一個項目,您需要復制其所有組件:

 .form__search {} .form__submit {}

使用塊和元素作為類名解決了一個重要問題:它幫助我們擺脫了嵌套選擇器。 BEM 項目中的所有選擇器具有相同的權重。 這意味著重新定義根據 BEM 編寫的樣式要容易得多。 現在,要在另一個項目中使用相同的表單,您只需複制其佈局和样式即可。

BEM 組件命名的想法是您可以顯式定義塊與其元素之間的連接。

修飾符和混合

官方上,“M”代表M修飾符,但它也暗示了 BEM 中一個更重要的概念:“混合”。 修飾符和混合都會對塊及其元素進行更改。 讓我們仔細看看這個。

修飾符

修飾符定義塊或元素的外觀、狀態和行為。 添加修飾符是可選的。 修改器允許您組合不同的塊功能,因為您可以使用任意數量的修改器。 但是不能為塊或元素分配相同修飾符的不同值。

讓我們探索修飾符是如何工作的。

想像一下,該項目需要與上面示例中相同的搜索表單。 它應該具有相同的功能但看起來不同(例如,頁眉和頁腳中的搜索表單應該不同)。 改變表單外觀的第一件事是編寫額外的樣式:

 header .form {} footer .form {}

header .form選擇器比form選擇器具有更大的權重,這意味著一條規則將覆蓋另一條規則。 但正如我們所討論的,嵌套選擇器增加了代碼耦合,使重用變得困難,所以這種方法對我們不起作用。

在 BEM 中,您可以使用修飾符將新樣式添加到塊中:

 <!-- Added the form_type_original modifier--> <form class="form form_type_original" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

<form class="form form_type_original"></form>行表示該塊被分配了具有original值的type修飾符。 在經典方案中,修飾符名稱與塊或元素名稱用下劃線分隔。

表單可以具有獨特的顏色、大小、類型或設計主題。 所有這些參數都可以使用修飾符設置:

 <form class="form form_type_original form_size_m form_theme_forest"> <form class="form form_type_original form_size_m form_theme_forest">

相同的表格可以看起來不同但尺寸保持不變:

 <form class="form form_type_original form_size_m form_theme_forest"></form> <form class="form form_type_original form_size_m form_theme_sun"></form>

但是每個修飾符的選擇器仍然具有相同的權重:

 .form_type_original {} .form_size_m {} .form_theme_forest {}

重要提示修飾符僅包含以某種方式更改原始塊實現的附加樣式。 這允許您只設置一次通用塊的外觀,並且僅將與原始塊代碼不同的那些功能添加到修飾符樣式中。

 .form { /* universal block styles */ } .form_type_original { /* added styles */ }

這就是為什麼修飾符應該始終與塊及其關聯的元素位於同一個 DOM 節點上的原因。

 <form class="form form_type_original"></form>

在非常特殊的情況下,您可以使用修飾符來應用通用組件。 塊和元素代碼不會改變。 在 DOM 節點上創建必要的修飾符組合。

混音

混合允許您將相同的格式應用於不同的 HTML 元素,並結合多個實體的行為和样式,同時避免代碼重複。 它們可以替換抽象包裝塊。

混合意味著您在單個 DOM 節點上託管多個 BEM 實體(塊、元素、修飾符)。 與修改器類似,混合用於更改塊。 讓我們看一些什麼時候應該使用混音的例子。

塊不僅可以在視覺上而且在語義上也可以不同。 例如,搜索表單、註冊表單和訂購蛋糕的表單都是表單。 在佈局中,它們是用“表單”塊實現的,但它們沒有任何共同的樣式。 用修飾符處理這種差異是不可能的。 您可以為此類塊定義通用樣式,但您將無法重用代碼。

 .form, .search, .register { ... }

您可以使用混合為同一表單創建語義不同的塊:

 <form class="form" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

.form類選擇器描述了可以應用於任何表單(訂單、搜索或註冊)的所有樣式:

 .form {}

現在您可以從通用表單中創建一個搜索表單。 為此,請在項目中創建一個額外的search類。 這個類將只負責搜索。 要組合.form.search類的樣式和行為,請將這些類放在一個 DOM 節點上:

 <form class="form search" action="/"> <input class="form__search" name="s"> <input class="form__submit" type="submit"> </form>

在這種情況下, .search類是定義行為的單獨塊。 這個塊不能有負責形式、主題和大小的修飾符。 這些修飾語已經屬於通用形式。 混合有助於組合這些塊的樣式和行為。

讓我們再舉一個組件的語義發生變化的例子。 這是頁眉中的導航菜單,其中所有條目都是鏈接:

 <nav class="menu"> <a class="link" href=""></a> <a class="link" href=""></a> <a class="link" href=""></a> </nav>

鏈接功能已在link塊中實現,但菜單鏈接必須在視覺上與文本中的鏈接不同。 有幾種方法可以更改菜單鏈接:

  1. 創建一個菜單條目修飾符,將條目轉換為鏈接:
     <nav class="menu"> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> <a class="menu__item menu__item_link" href=""></a> </nav>

    在這種情況下,要實現修飾符,您應該複製 `link` 塊的行為和样式。 這將導致代碼重複。
  2. 混合使用 `link` 通用塊和 `menu` 塊的 `item` 元素:
     <nav class="menu"> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> <a class="link menu__item" href=""></a> </nav>

    通過混合兩個 BEM 實體,您現在可以從 `link` 塊實現基本鏈接功能,並從 `menu` 塊實現額外的 CSS 規則,並避免代碼重複。

外部幾何和定位:放棄抽象 HTML 包裝器

混合用於相對於其他塊定位塊或定位塊內的元素。 在 BEM 中,負責幾何和定位的樣式在父塊中設置。 讓我們看一個必須放在標題中的通用菜單塊。 在佈局中,塊必須從父塊縮進 20px。

這個任務有幾個解決方案:

  1. 為菜單塊編寫帶有縮進的樣式:
     .menu { margin-left: 20px; }

    在這種情況下,“菜單”塊不再通用。 如果必須將菜單放在頁腳中,則必須編輯樣式,因為縮進可能會有所不同。
  2. 創建菜單塊修改器:
     <div> <ul class="menu menu_type_header"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>
     .menu_type_header { margin-left: 20px; } .menu_type_footer { margin-left: 30px; }

    在這種情況下,該項目將包括兩種菜單,但事實並非如此。 菜單保持不變。
  3. 定義塊的外部定位:將`menu`塊嵌套在抽象包裝器中(例如,`wrap`塊)設置所有縮進:
     <div class="wrap"> <ul class="menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

    為了避免創建修飾符和更改塊樣式以將塊定位在頁面上的誘惑,您需要了解一件事:

    父塊的縮進不是嵌套塊的特徵。 這是父塊的一個特性。 它必須知道嵌套塊必須從邊界縮進一定數量的像素。
  4. 使用混合。 有關嵌套塊定位的信息包含在父塊元素中。 然後將父塊元素混合到嵌套塊中。 在這種情況下,嵌套塊沒有指定任何縮進,並且可以在任何地方輕鬆重用。

讓我們繼續我們的例子:

 <div> <ul class="menu header__menu"> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> <li class="menu__item"><a href=""></a></li> </ul> </div>

在這種情況下, menu塊的外部幾何形狀和位置是通過header__menu元素設置的。 menu塊沒有指定任何縮進並且可以很容易地重複使用。

父塊元素(在我們的例子中是header__menu )執行負責塊外部定位的包裝塊的任務。

文件結構中的塊

所有 BEM 項目都具有相似的文件結構。 熟悉的文件結構使開發人員可以更輕鬆地導航項目、在項目之間切換以及將塊從一個項目移動到另一個項目。

每個塊的實現都存儲在單獨的項目文件夾中。 每種技術(CSS、JavaScript、測試、模板、文檔、圖像)都在一個單獨的文件中。

例如,如果使用 CSS 設置input塊外觀,則代碼保存在input.css文件中。

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript

修飾符和元素的代碼也存儲在塊的單獨文件中。 這種方法允許您在構建中僅包含實現塊所需的那些修飾符和元素。

 project common.blocks/ input/ input.css # The "input" block implementation with CSS input.js # The "input" block implementation with JavaScript input_theme_sun.css # The "input_theme_sun" modifier implementation input__clear.css # The "input__clear" element implementation with CSS input__clear.js # The "input__clear" element implementation with JavaScript

為了改進項目導航,將塊修飾符與目錄中的多個值結合起來。

任何 BEM 項目的文件結構都由重新定義級別組成(您可以在此處了解有關它們的更多信息)。 重新定義級別允許您:

  • 將項目劃分為平台;
  • 輕鬆更新項目中包含的塊庫;
  • 使用通用塊開發多個項目;
  • 在不影響項目邏輯的情況下改變設計主題;
  • 在現場項目中進行實驗。

使用塊並將所有塊技術存儲在同一個文件夾中,可以輕鬆地在項目之間移動塊。 要將塊的所有樣式和行為與佈局一起移動,只需將塊文件夾複製到新項目即可。

方法論的非明顯優勢

並行開發的便利

在 BEM 中,任何佈局都分為塊。 由於塊是獨立的,它們可以由多個開發人員並行開發。

開發人員創建一個塊作為可以在任何其他項目中重用的通用組件。

一個示例是 bem-components 塊庫,其中包含通用塊,例如鍊接、按鈕和輸入字段。 從通用組件創建更複雜的塊更容易。 例如,選擇器或複選框。

在項目佈局中使用塊可以幫助您節省集成多個開發人員編寫的代碼的時間,保證組件名稱的唯一性,並讓您可以在開發階段測試塊。

測試佈局

測試整個頁面的功能是有問題的,尤其是在連接到數據庫的動態項目中。

在 BEM 中,每個塊都被測試覆蓋。 測試是一種塊實現技術,如 Javascript 或 CSS。 塊在開發階段進行測試。 更容易檢查一個塊的正確性,然後從測試的塊組裝項目。 之後,您所要做的就是確保塊包裝器正常工作。

可定制的項目構建

為了方便開發,BEM 項目中的所有模塊和技術都放在單獨的文件夾和文件中。 要將源文件合併到一個文件中(例如,將所有 CSS 文件放在project.css中,將所有 JS 文件放在project.js中,等等),我們使用構建過程。

構建執行以下任務:

  • 組合分佈在項目文件系統中的源文件;
  • 僅包括項目中必要的塊、元素和修飾符(BEM 實體);
  • 遵循包含實體的順序;
  • 在構建期間處理源文件代碼(例如,將 LESS 代碼編譯為 CSS 代碼)。

要在構建中僅包含必要的 BEM 實體,您需要創建頁面上使用的塊、元素和修飾符的列表。 此列表稱為聲明

由於 BEM 塊是獨立開發的,並放置在文件系統中的單獨文件中,因此它們彼此不“了解”任何信息。 要基於其他塊構建塊,請指定依賴項。 有一種 BEM 技術對此負責: deps.js文件。 依賴文件讓構建引擎知道項目中必須包含哪些附加塊。

實際案例:BEM 不僅僅適用於 CSS

在前面的部分中,所有代碼示例都是針對 CSS 的。 但是 BEM 允許您以與 CSS 中相同的聲明方式修改塊的行為及其在 HTML 中的表示。

如何在 BEM 中使用模板

在 HTML 中,每次塊出現在頁面上時都會重複塊標記。 如果您手動創建 HTML 標記,然後需要修復錯誤或進行更改,您將需要修改塊的每個實例的標記。 為了自動生成 HTML 代碼並應用修復,BEM 使用模板; 塊負責它們在 HTML 中的呈現方式。

模板允許您:

  • 減少用於項目調試的時間,因為模板更改會自動應用於所有項目塊;
  • 修改區塊佈局;
  • 將具有當前佈局的塊移動到另一個項目。

BEM 使用具有兩個引擎的 bem-xjst 模板引擎:

  • BEMHTML
    將頁面的 BEMJSON 描述轉換為 HTML。 模板在 .bemhtml.js 文件中描述。
  • 貝姆特里
    將數據轉換為 BEMJSON。 模板在.bemtree.js文件中以 BEMJSON 格式描述。

如果沒有為塊編寫模板,則模板引擎默認為塊設置<div>標籤。

比較塊的聲明和 HTML 輸出:

宣言:

 { block: 'menu', content: [ { elem: 'item', content: { block: 'link'} }, { elem: 'item', elemMods: { current: true }, // Set the modifier for the menu item content: { block: 'link' } } ] }

HTML:

 <div class="menu"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div>

要修改menu塊佈局,您需要為該塊編寫模板:

  1. 讓我們更改menu塊標籤:
     block('menu')( tag()('menu') // Set the "menu" tag for the menu block )

    修改後的 HTML:
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </menu>

    與 CSS 類似,模板適用於頁面上的所有“菜單”塊。
  2. 添加一個額外的元素 ( menu__inner ) 作為內部包裝器並負責menu塊中元素的佈局。 最初menu__inner元素沒有包含在聲明中,所以我們必須在構建模板時添加它。

    BEM 模板是用 JavaScript 編寫的,因此您也可以使用 JavaScript 向模板添加新元素:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content }; }) )
     <menu class="menu"> <!-- Replace the "div" tag with the "menu" tag for the "menu" block --> <div class="menu__inner"> <div class="menu__item"> <div class="link"></div> </div> <div class="menu__item menu__item_current"> <div class="link"></div> </div> </div> </menu>
  3. 替換所有inneritem元素的標籤:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) )
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <div class="link"></div> </li> <li class="menu__item menu__item_current"> <div class="link"></div> </li> </ul> </menu>
  4. 為頁面上的所有鏈接設置<a>標籤:
     block('menu')( tag()('menu'), content()(function() { return { elem: 'inner', content: this.ctx.content } }), elem('inner')( tag()('ul') ), elem('item')( tag()('li') ) ); block('link')( tag()('a') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <a class="link"></a> </li> <li class="menu__item menu__item_current"> <a class="link"></a> </li> </ul> </menu>
  5. 修改現有模板。 模板中規則的應用方式與 CSS 中相同:較低的規則覆蓋較高的規則。 向模板添加新規則,並將鏈接標籤從<a>更改為<span>
     block('link')( tag()('a') ); block('link')( tag()('span') );
     <menu class="menu"> <ul class="menu__inner"> <li class="menu__item"> <span class="link"></span> </li> <li class="menu__item menu__item_current"> <span class="link"></span> </li> </ul> </menu>

BEM 是一個可定制的系統

BEM 方法為您提供了在項目中創建系統的嚴格規則。 但同時可以自定義很多邊界元規則。 BEM 方法允許您更改命名約定、選擇最方便的文件結構或將您想要的任何技術添加到塊中。

現在您可以調入系統並製作您自己的 BEM 超級英雄!

BEM 作為美國隊長的標誌
BEM 美國隊長

如何從 BEM 中獲得更多收益

要開始學習 BEM 原理,請訪問我們的網站。 如果您有任何問題想向團隊提問,請加入我們的 Telegram 頻道或在我們的 BEM 論壇中進行討論。