命名约定
若是使用 BEM 实体,就需要了解它的命名规则。
命名约定的理念就是使得 CSS 选择器的命名尽可能的直观,尽可能的简单。这将使得开发和调试更容易,也解决了 web 开发者所面临的一些问题。
现在,我们有一个名字为 menuitemvisible
的 CSS 选择器。然而,对直观来看,对这样一个选择器名称,我们不能快速地从中确定 BEM 实体的类型。
让我们添加一个分隔符:
menu-item-visible
或者 menuItemVisible
像上面这样写,选择器的名称被清晰地分割成不同逻辑部分。我们可以假定 menu
是一个模块,item
是一个元素,visible
是一个修饰符。然而,真实的例子通常是复杂的,并没有如此的简单,这正是 BEM 命名约定的用武之处。
BEM 方法论为创建命名规则提供了一种思路,并且遵循这种思路来规范 CSS 选择器命名约定。然而,在 web开发的世界中也有许多基于 BEM 原则的替代方案。
CSS 选择器命名约定
- 使用数字和小写的拉丁文字符书写 BEM 实体名称。
- 名字中的每一个单词使用连字符(-)分隔开来。
- 关于模块,元素和修饰符的名字信息存储在 CSS 类中。
命名规则:
- 模块
- 元素
- 修饰符
模块名称
一个模块遵循 block-name
的格式,相当于为元素和修饰符定义了一个命名空间。
有时,模块名称可以添加不同的前缀。
例子
menu
lang-switcher
HTML
<div class="menu">...</div>
CSS
.menu {color: red;}
元素名称
由模块的名称定义的命名空间决定了一个元素属于这个模块。一个元素的名称使用双下划线(__)与模块名称相分隔。
使用如下的方式创建一个元素的全名:
block-name__elem-anem
如果一个模块拥有几个完全相同的元素,就像菜单项这个例子中,所有相同的元素将有相同的名字 menu__item
。
重要提示!BEM 方法论中,在元素内部嵌套元素是不被推荐的(译者注:意思就是使用这样的命名block__elem1__elem2
是不被推荐的。)
例子
menu_item
lang-switcher__lang-icon
HTML
<div class="menu">...<span class="menu_item"></span></div>
CSS
.menu__item { color: red; }
修饰符名称
由模块或者元素的名称定义的命名空间,决定了一个修饰符属于这个模块或元素。一个修饰的名字使用一个单下划线与前面的模块或元素名称相分隔。
使用下面的方式创建一个修饰符的全名:
- Boolean类型的修饰符 ——
owner-name_mod-name
。 - key-value 类型的修饰符 ——
owner-name_mod-name_mod-val
。
重要提示!在 BEM 方法论中,一个修饰符不能再它所属的上下文环境之外被使用
模块修饰符
-
Boolean 类型的修饰符。这种类型的修饰符的值不需要明确指定。使用下面的方式创建这种修饰符的全名:
block-name_mod-name
例子
menu_hidden
-
key-value类型的修饰符。这种类型的修饰符使用单下划线(_)将其值与修饰符的名称相分隔。使用
block-name_mod-name_mod-val
的方式创建一个修饰符的全名。
例子
menu_theme_morning-forest
HTML
<div class="menu menu_hidden">...</div>
<div class="menu menu_theme_morning-forest">...</div>
<!-- 不正确的 -->
<div class="menu_hidden">...</div>
<!-- 这里丢失了有修饰符影响的模块的名称 -->
CSS
.menu_hidden { display: none; }
.menu_theme_morning-forest {color: green;}
元素修饰符
-
Boolean 类型的修饰符。这种类型的修饰符的值不需要明确指定。使用下面的方式创建这种修饰符的全名:
block-name__elem-name_mod-name
.
例子
menu__item_visible
- Key-value 类型的修饰符。
例子
menu__item_type_radio
HTML
<div class="menu"> ... <span class="menu__item menu__item_visible menu__item_type_radio"></span> </div>
CSS
.menu__item_type_radio { color: blue; }
使用命名约定的一个例子
使用 HTML 和 CSS 实现的一个认证表单
HTML
<form class="form form_login form_theme_forest">
<input class="form__input">
<input class="form__submit form__submit_disabled">
</form>
CSS
.form {}
.form_theme_forest {}
.form_login {}
.form__input {}
.form__submit {}
.form__submit_disabled {}
可供选择的命名方案
这里有一些可供选择的基于 BEM 命名约定的方案。
Two Dashes style(双连字符风格)
block-name__elem-name--mod-name
- 名字全部使用小写。
- BEM 实体的名称中的每一个单词使用一个连字符分隔。
- 使用双下划线(__)将元素的名称和模块的名称分离开。
- 使用双连字符(--)分隔 Boolean 类型的修饰符。
- 不使用 key-value 类型的修饰符
重要提示!在注释中,双连字符被视为注释的一部分,因此在文档验证时,双破折号可能会引起错误。HTML5 Specification
CamelCase style(驼峰命名风格)
MyBlock__SomeElem_modName_modVla
这种风格的命名方案的不同点在于,在 BEM 实体中分隔单词时使用驼峰命名法代替了一个连字符(-)。
"Sans underscore" style(无下划线风格)
blockName-elemName--modName--modVal
- 名称使用驼峰命名法书写。
- 元素名称与模块名称使用一个连字符(-)分隔。
- 修饰符使用双连字符(--)与模块或元素分隔,
- 修饰符的名称和值使用双连字符(--)分隔。
重要提示!
在注释中,双连字符被视为注释的一部分,因此在文档验证时,双破折号可能会引起错误。HTML5 Specification
No namespace style(无命名空间风格)
_available
这种风格的特征在于修饰符的前面没有模块或元素的名称与其相连。这种方式限制了使用混合模式,这是由于并不能确定这个修饰符属于哪个模块或元素。
选择哪一种风格
BEM 方法论为 BEM 实体的命名提供了基本的原则。选择哪一种命名方式取决于你项目的需求和你的个人喜好。使用方法论中提到的命名约定的一大优势在于具有现成的面向“经典命名”的开发工具。
除此之外,BEM 方法论不仅仅局限于在本文讨论的 HTML 和 CSS 技术,模块,元素和修饰符的概念同样适用于 JavaScript ,模板技术和 BEM 项目的文件结构中。bem-naming工具使我们可以在所有可以使用到的实现技术中使用相同命名的 BEM 实体。
默认情况下,bem-naming
工具的配置默认为方法论中提到的命名约定,但是你可以添加你自己规则进去。