[译]跟着例子学 BEM 命名约定

2,962 阅读5分钟

原文:BEM by Example, by Nathan Rambeck.

BEM 一个流行的类名约定标准,它的基本概念很简单,但对于新手而言,刚接触时也会碰到一些误区,本文将通过一系列例子来解释常见的使用误区。

BEM(是 Block-Element-Modifier 的简写形式)是一个 CSS 类名的命名标准。现在已被广泛使用,用来编写易于阅读、理解和扩展的 CSS 代码。

为什么是 BEM

使用 BEM 命名方式有如下三点好处:

  1. 命名本身能够传达功能或目的
  2. 命名本身能够传达组件结构
  3. 它是由一系列低权重选择器组成的

BEM 的工作原理

使用 BEM 方式组织的类名由以下三部分组成:

  1. 块(Block):组件的最外层的祖先元素定义为块。
  2. 元素(Element):组件内部中的后代元素,可能是一个可能是多个。
  3. 修饰符(Modifier):表示块或元素的一个变体。

如果上面三部分全部使用,BEM 的书写形式看起来是这样的:

[block]__[element]--[modifier]

经过简短的介绍之后,我们下面来看一些具体的例子。

例子

组件

有些组件简单到只用一个元素就能表达出来,这个单独的类就是块。

<button class="btn"></button>

<style>
  .btn {}
</style>

带修饰符的组件

组件可能会有变体。组件变体使用修饰符来实现。

<!-- 这样写 -->
<button class="btn btn--secondary"></button>

<style>
  .btn {
    display: inline-block;
    color: blue;
  }
  .btn--secondary {
    color: green;
  }
</style>  

修饰符是配合基础类使用的,不能单独使用,修饰符中也不会包含基础样式。

<!-- 不要这样写 -->
<button class="btn--secondary"></button>

<style>
  .btn--secondary {
    display: inline-block;
    color: green;
  }  
</style>

包含元素的组件

较复杂的组件包含后代元素,每一个需要赋予样式的元素都应该有一个名称。

使用 BEM 的目的之一是为了低权重和一致性。不要忽略后代元素的类名,否则你只能通过增加权重的方式为这些裸露的元素赋样式(下面代码里的 imgfigcap 就是例子)。不使用类名可能结构看上去更简洁,但却增加了未来出现级联问题的风险。BEM 的一个目标是让大多数选择器只使用一个类名。

<!-- 这样写 -->
<figure class="photo">
  <img class="photo__img" src="me.jpg">
  <figcaption class="photo__caption">Look at me!</figcaption>
</figure>

<style>
  .photo { } /* 权重 10 */
  .photo__img { } /* 权重 10 */
  .photo__caption { } /* 权重 10 */
</style>

<!-- 不要这样写 -->
<figure class="photo">
  <img src="me.jpg">
  <figcaption>Look at me!</figcaption>
</figure>

<style>
  .photo { } /* 权重 10 */
  .photo img { } /* 权重 11 */
  .photo figcaption { } /* 权重 11 */
</style>

如果组件中包含多个层次的后代元素,不要试图在类名中表现出每一层。BEM 不是为了传达结构深度。BEM 表达的是组件中的一个后代元素,类名是由块和元素组成。下面的例子里,.photo__caption__quote 不是正确的 BEM 写法,.photo__quote 才是。

<!-- 这样写 -->
<figure class="photo">
  <img class="photo__img" src="me.jpg">
  <figcaption class="photo__caption">
    <blockquote class="photo__quote">
      Look at me!
    </blockquote>
  </figcaption>
</figure>

<style>
  .photo { }
  .photo__img { }
  .photo__caption { }
  .photo__quote { }
</style>


<!-- 不要这样写 -->
<figure class="photo">
  <img class="photo__img" src="me.jpg">
  <figcaption class="photo__caption">
    <blockquote class="photo__caption__quote"> <!-- 类名中出现的后代元素不能多于一个 -->
      Look at me!
    </blockquote>
  </figcaption>
</figure>

<style>
  .photo { }
  .photo__img { }
  .photo__caption { }
  .photo__caption__quote { }
</style>

带修饰符的元素

在某些情况下,你可能希望修改组件中的某个元素的样式。这时候,应该给元素而不是组件添加修饰符。当然,相比于修改整个组件,修改组件中某个元素的场景不太常见,用处也小。

<figure class="photo">
  <img class="photo__img photo__img--framed" src="me.jpg">
  <figcaption class="photo__caption photo__caption--large">Look at me!</figcaption>
</figure>

<style>
  .photo__img--framed {
    /* 增量样式修改 */
  }
  .photo__caption--large {
    /* 增量样式修改 */
  }
</style>

基于组件修饰符书写样式

如果你发现自己总是以相同的方式修改某个组件里的多个元素,那么可以考虑将修饰符添加到组件的基类名上,并根据这个修饰符的含义,调整每个后代元素的样式。这种方式会增加选择器权重,但让修改组件样式变得更简单了。

<!-- 这样写 -->
<figure class="photo photo--highlighted">
  <img class="photo__img" src="me.jpg">
  <figcaption class="photo__caption">Look at me!</figcaption>
</figure>

<style>
  .photo--highlighted .photo__img { }
  .photo--highlighted .photo__caption { }
</style>

<!-- 不要这样写 -->
<figure class="photo">
  <img class="photo__img photo__img--highlighted" src="me.jpg">
  <figcaption class="photo__caption photo__caption--highlighted">Look at me!</figcaption>
</figure>

<style>
  .photo__img--highlighted { }
  .photo__caption--highlighted { }
</style>

多词名称

BEM 名称故意使用双下划线和双连字符,来分隔块-元素-修饰符。如果使用的名称中包含多个单词,那么就可以使用一个连字符连接这多个单词。这样的类名更加易读,同时,应该尽量避免使用缩写,除非这个缩写是大家普遍知道的。

<!-- 这样写 -->
<div class="some-thesis some-thesis--fast-read">
  <div class="some-thesis__some-element"></div>
</div>

<style>
  .some-thesis { }
  .some-thesis--fast-read { }
  .some-thesis__some-element { }
</style>

<!-- 不要这样写
    名称读起来很费劲
-->
<div class="somethesis somethesis--fastread">
  <div class="somethesis__someelement"></div>
</div>

<style>
  .somethesis { }
  .somethesis--fastread { }
  .somethesis__someelement { }
</style>

让人欢喜的 BEM

如果你现在还没有开始使用 BEM,那我强烈建议你在下一个项目中使用它。它可能与你已有的书写习惯不同,但我相信你很快就能看到使用它为项目带来的好处。

希望上面的这些例子能帮助你避免,大多数人在第一次使用这种古怪的命名约定时所犯的一些常见错误。

(完)