BEM隨筆記

紀錄一些 BEM 在使用時可能會碰到的問題。

對 Modifier 下的 Element 定義新的規則

假使我們有一個卡片組件如下:

1
2
3
4
5
6
<article class="card">
<h2 class="card__title">...</h2>
<p class="card__text">...</p>
<p class="card__text card__text--secondary">...</p>
<a class="card__button" href="#">...</a>
</article>

card

現在我們想要定義一個新的 Modiefier, card--feature,會長這樣子。

card-feature

除了 card--feature 的背景顏色會改變之外, 其下的 card__title, card__text, card__button 也都要做修改,這種時候該怎麼寫才好?

有些人會這樣子寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.card {
// ...
&__title {
// ...
}
&__text {
// ...
}
&__button {
// ...
}
/*
--feature 跟 .card 都是指到同個元素
所以下面的 Element 都是同樣的:
(.card > card__title) === (.card--feature > card--feature__title)
*/
&--feature {
// ...
.card__title {
// ...
}
.card__text {
// ...
}
.card__button {
// ...
}
}
}

但如果今天要改 class 名稱的時候,要修改的地方就會變很多。

所以建議你可以這樣子寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.card {
// ...
&__title {
// ...
}
&__text {
// ...
}
&__button {
// ...
}
/*
--feature 跟 .card 都是指到同個元素
所以下面的 Element 都是同樣的:
(.card > card__title) === (.card--feature > card--feature__title)
*/
&--feature {
// ...
}
&--feature &__title {
// ...
}
&--feature &__text {
// ...
}
&--feature &__button {
// ...
}
}

這樣子要改 class 名稱時,只要改最外層那個 card 就解決囉。

🚀 Codepen:點這裡

什麼時候不該寫成 BEM

當有一個 class 是可以獨立存在的時候

例如:

1
2
3
.clearfix {
clear: both;
}

雖然按照 BEM 的規則,你可以把它歸類成Modifier
但它其實是一個可以獨自存在的 class,而且可以用在網頁的各種地方。
所以比起寫成modifier,把它歸類為一個單獨存在的 class,或許會更適合。

適合模組化的時機

假設你的 HTML 結構長這樣:

1
2
3
4
5
6
7
<div class="content">
<ul class="menu">
<li class="item">menu1</li>
<li class="item">menu2</li>
<li class="item">menu3</li>
</ul>
</div>

你可能會很直覺的寫成content__menu這種結構。
但是如果你這樣子寫,意思就會是,menucontent 區塊綁在一起。

那如果網頁中有其他的地方也會有選單的話呢?
你就沒辦法直接拿menu這個模組來用了,因為它跟content綁在一起了。

所以我們透過 BEM 來建立每個模組的時候要思考一件事:
「這個區塊有沒有可能會在網頁的其他地方出現」

所以回到上面的例子。
比起讓menu作為content下的Elementmenu更適合當作是一個Block
這樣子menu會成為一個模組,也就有更高的靈活性。

一個 Block 下最多只會連接一個 Element

這裡引用來自BEM by Example的一段敘述:

If your component has child elements several levels deep, don’t try to represent each level in the class name. BEM is not intended to communicate structural depth. A BEM class name representing a child element in the component should only include the base/block name and the one element name.

意思是說,假使一個 component 下有多個層級的子元素,我們也不必在 BEM 把每一層的結構寫出來,譬如說:

1
2
3
4
5
6
7
8
9
<figure class="photo">
<img class="photo__img" src="image.jpg" />
<figcaption class="photo__caption">
圖片解說
<blockquote class="photo__caption__quote">
不要在一個class裡面放一個以上的element
</blockquote>
</figcaption>
</figure>

所以一個Block下最多只會寫一層Element

1
2
3
4
5
6
7
<figure class="photo">
<img class="photo__img" src="image.jpg" />
<figcaption class="photo__caption">
圖片解說
<blockquote class="photo__quote">這樣就對了</blockquote>
</figcaption>
</figure>

即便你沒有把每一個層級都寫出來,也能夠看出img, caption, quote都是photo這個 component 下的元素。

所以只要掌握住一個原則:這個元素是哪個 component 下的元素,就能寫出簡潔清楚的 class 名稱。

有些元素不需要綁在 Block 上

拿我在Frontend Mentor挑戰中的header部分來舉例:

1
2
3
4
<header class="header">
<h3 class="slogan">WE ARE CREATIVES</h3>
<a class="arrow"><img class="pic" src="arrow.jpg" /></a>
</header>

sloganarrow這兩個元素其實都能獨自存在,並沒有一定要綁在header這個Block上(除非你把整個header當成是一個 component),所以就不建議這樣子寫:

1
2
3
4
<header class="header">
<h3 class="header__slogan">WE ARE CREATIVES</h3>
<a class="header__arrow"><img class="header__pic" src="arrow.jpg" /></a>
</header>

這種情況大多會發生在文字的部分,所以這種時候就建議寫一個方便識別的 class 就好,不用一定要照著 BEM 的規則來命名。

參考資料

BEM by Example
竹白記事本-BEM,CSS 設計模式
IT 人-[譯] CSS 使用 BEM 命名規範的五大理由

日常英文用語 SCSS隨筆記
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×