BEM(Block-Element-Modifier)是CSS类名的命名约定标准。它具有相当广泛的采用,并且在编写更易于阅读、理解和扩展的CSS方面非常有用。
为什么选择BEM
BEM命名提供了三个特定的好处:
- 它传达目的或功能。
- 它传达组件结构。
- 它为样式选择器设置了一致的低级特异性。
这个怎么运作
BEM类名最多包含三个部分:
- 块:组件的最外层元素被定义为块。
- 元素:组件内部可能有一个或多个子元素,称为元素。
- 修饰符:一个块或元素都可以有一个修饰符表示的变化。
如果这三个都用在一个名称中,它看起来像这样:
[block]__[element]--[modifier]
例子
没有元素或修饰符的组件
简单组件可能只使用单个元素,因此单个类会成为块。
<button class="btn"></button>
<style>
.btn {}
</style>
带有修饰符的组件
一个组件可能有一些变化。应该使用修饰符类来实现变体。
<!-- DO THIS -->
<button class="btn btn--secondary"></button>
<style>
.btn {
display: inline-block;
color: blue;
}
.btn--secondary {
color: green;
}
</style>
不要单独使用修饰符。修饰符旨在扩充而不是替换基类。
<!-- DON'T DO THIS -->
<button class="btn--secondary"></button>
<style>
.btn--secondary {
display: inline-block;
color: green;
}
</style>
带元素的组件
更复杂的组件会有子元素。每个需要样式的子元素都应该包含一个类。
BEM背后的目的之一是保持特异性低且一致。不要在HTML的子元素中省略类名。这将迫使您使用具有更高特异性的选择器来设置组件内的元素的样式(请参阅下面的img的figcaption元素)。BEM的一个目标是让大多数选择器只使用一个类名。
<!-- DO THIS -->
<figure class="photo">
<img class="photo__img" src="me.jpg">
<figcaption class="photo__caption">Look at me!</figcaption>
</figure>
<style>
.photo {}
.photo__img {}
.photo__caption {}
</style>
<!-- DON'T DO THIS -->
<figure class="photo">
<img src="me.jpg">
<figcaption>Look at me!</figcaption>
</figure>
<style>
.photo {}
.photo img {}
.photo figcaption {}
</style>
如果组件有几个级别的子元素,请不要尝试在类名中表示每个级别。BEM并非旨在传达结构深度。代表组件中子元素的BEM类名应该仅包括基/块名和一个元素名称。在下面的示例中,请注意photo__caption__quote是BEM的错误使用,用photo__quote更合适。
<!-- DO THIS -->
<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>
<!-- DON'T DO THIS -->
<figure class="photo">
<img class="photo__img" src="me.jpg">
<figcaption class="photo__caption">
<blockquote class="photo__caption__quote"><!-- never include more than one child element in a class name -->
Look at me!
</blockquote>
</figcaption>
</figure>
<style>
.photo {}
.photo__img {}
.photo__caption {}
.photo__cpation__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 {}
.phoot__caption--large {}
</style>
基于组件修饰符的样式元素
如果您发现自己以相同的方式不断地修改同一组件的元素,则考虑将修饰符添加到组件的基础,并根据该修饰符调整每个子元素的样式。这将增加特异性,但它使修改组件更加简单。
<!-- DO THIS -->
<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>
<!-- DON'T DO THIS -->
<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 名称有意使用双下划线和双连字符而不是单独一个来分隔 Block-Element-Modifier。原因是单个连字符可以用作单词分隔符。类名应该非常易读,因此缩写并不总是可取的,除非缩写是普遍可识别的。
<!-- DO THIS -->
<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>
<!-- DON'T DO THIS -->
// These class names are harder to read
<div class="somethesis somethesis--fastread">
<div class="somethesis__someelement"></div>
</div>
<style>
.somethesis { }
.somethesis--fastread { }
.somethesis__someelement { }
</style>