如何优雅的写 CSS —— BEM 规范

前端框架和库一直更新换代非常快,但是 CSS 却是一直没有多大的改变,每次都只是一点点,很难让人不吐槽。看了下别人的文章和代码,感觉自己需要学习的地方还有很多,所以打算做一个系列文章,分别讲一下 BEM 规范,SCSS 和 postCSS,也算是督促自己按照这个套路来写出更优雅的代码。

下面先从 BEM 规范开始讲起。写 CSS 必须要有一个好的规范,否则后续改起来会很麻烦,

BEM 全称是 Blocks(模块), Elements(元素) and Modifiers(修饰符)。


认识 BEM

  1. 模块
    这里所指是文档的一部分,例如头部 header,内容 content,底部 footer 等,也指比如 header 中的一部分—— header 中的 logo、login 等。

  2. 元素
    元素就是指模块中的元素,对于元素中嵌套的多层子元素,在写的时候不用每个都写出来,只需要写出最后一个即可,否则会非常恐怖的吧。

  3. 修饰符
    这个就是状态,比如 active、hover 等。

所以,一个完整的 BEM 就是最多只有 BEM 三级,B + E + M,每个 E 不能重名。


怎么写?

命名方式

对于一个模块,直接以相应名称命名。

<div class="menu">...</div>
.menu { color: red; }

对于元素,用两个下划线与模块名称相连。

<div class="menu">
...
<span class="menu__item"></span>
</div>
.menu__item { color: red; }

对于修饰符,分两种情况:

(1). 直接作用于模块上的修饰符,一定要带上单独的模块名称,不能省略

<div class="menu menu_hidden">...</div>
<div class="menu menu_theme_islands">...</div>
.menu_hidden { display: none }
.menu_theme_islands { color: green; }

不正确写法:

<div class="menu_hidden">...</div>

(2). 作用于元素上的修饰符,需要把模块_元素修饰符写完整

<div class="menu">
...
<span class="menu__item menu__item_visible menu__item_type_radio">...</span>
</div>
.menu__item_type_radio { color: blue; }

在不同组件内使用

其实在命名的时候,就要考虑进去。对于一些字体大小、颜色等,不能直接命名,而是根据程度来命名。

例如字体大小:

.lg{}
.md{}
.sm{}
.xs{}

这样在修改的时候,只需要修改相应的 class 就可以,不会出现挂羊头卖狗肉的现象(即 class 名和实际大小不符合的情况)。

例如你已经定义好一个 button 样式,在一个模块内也引用好了,但是突然有一天你需要改变这个按钮样式的时候,正确的做法是在按钮上添加修饰 class,而不是依赖上一级 class。

定义好的button:

<button class="c-button c-button--primary">Click me!</button>

在某一处引用:

<div class="c-card">
<div class="c-card__body">
<button class="c-button c-button--primary">Click me!</button>
</div>
</div>

需要改成小一点的圆角边框:

<button class="c-button c-button--rounded c-button--small">Click me!</button>

不要这样添加一个依赖上级的类后添加特定的样式:

<div class="c-card">
<div class="c-card__body">
<button class="c-button c-card__c-button">Click me!</button>
</div>
</div>

注意事项

  1. 不能使用标签选择器。例如:li 不能直接使用,而是需要添加 class 来使用,这样避免了污染 li 中的 li 的样式。

  2. 不能使用 id,只用 class。id 只能用于单一元素,所以要避免。

  3. 如果不习惯下划线方式可以替换成其他合适的方式

总结

其实 BEM 里面还有很多细节的东西,这个只能在实践的时候遇到了再说,具体可以参考相应的文章。

参考文章:

Battling BEM CSS: 10 Common Problems And How To Avoid Them

Naming convention

知乎问答:如何看待 CSS 中 BEM 的命名方式?