快速开始CSS BEM命名规范

介绍

BEM (Block, Element, Modifier)是一种基于组件的Web开发方法。 其观点是将用户界面划分为独立的块。 即使使用复杂的UI,界面开发也变得简单快捷,并且允许复用现有的代码。

Block

功能独立的页面组件,可以重复使用。 在HTML中,块由class属性表示。

特点:

块名称描述了它的目的(“它是什么?” - 菜单或按钮),而不是其状态(“它是什么样子”? - 红色或大)。

例子
<!-- Correct. The `error` block is semantically meaningful -->
<div class="error"></div>

<!-- Incorrect. It describes the appearance -->
<div class="red-text"></div>
  • 该块不应影响其环境,这意味着您不应设置块的外部边距或定位。
  • 使用BEM时也不应使用标签或ID选择器。

这确保了重新使用块或将它们从一个地方移动到另一个地方是好的。

块使用指南

嵌套

  • blocks 能够相互嵌套
  • 你可以有任意层级的嵌套
例子
<!-- `header` block -->
<header class="header">
    <!-- Nested `logo` block -->
    <div class="logo"></div>

    <!-- Nested `search-form` block -->
    <form class="search-form"></form>
</header>

Element

块的组成部分,它不能离开块独立使用。

特点:

  • 元素名称描述其目的(“这是什么?” - 类目,文本等),而不是其状态(“什么类型,或什么样子”? - 红色,大等)。
  • 元素全名的结构是block-name__element-name。 元素名称与块名称以双下划线(__)分隔开。
例子
<!-- `search-form` block -->
<form class="search-form">
    <!-- `input` element in the `search-form` block -->
    <input class="search-form__input">

    <!-- `button` element in the `search-form` block -->
    <button class="search-form__button">Search</button>
</form>

元素使用指南

  • 嵌套
  • 成员
  • 可选

嵌套

  • 元素之间可以相互嵌套
  • 你可有任意层级的嵌套
  • 元素总是block的一部分,而不是另一个元素的一部分。这意味着元素名称不能定义在元素的层次结构下,比如block__elem1__elem2
例子
<!--
    Correct. The structure of the full element name follows the pattern:
    `block-name__element-name`
-->
<form class="search-form">
    <div class="search-form__content">
        <input class="search-form__input">

        <button class="search-form__button">Search</button>
    </div>
</form>

<!--
    Incorrect. The structure of the full element name doesn't follow the pattern:
    `block-name__element-name`
-->
<form class="search-form">
    <div class="search-form__content">
        <!-- Recommended: `search-form__input` or `search-form__content-input` -->
        <input class="search-form__content__input">

        <!-- Recommended: `search-form__button` or `search-form__content-button` -->
        <button class="search-form__content__button">Search</button>
    </div>
</form>

成员

一个元素总是一个block的一部分,你不能离开了block单独使用元素。

例子
<!-- Correct. Elements are located inside the `search-form` block -->
<!-- `search-form` block -->
<form class="search-form">
    <!-- `input` element in the `search-form` block -->
    <input class="search-form__input">

    <!-- `button` element in the `search-form` block -->
    <button class="search-form__button">Search</button>
</form>

<!--
    Incorrect. Elements are located outside of the context of
    the `search-form` block
-->
<!-- `search-form` block -->
<form class="search-form">
</form>

<!-- `input` element in the `search-form` block -->
<input class="search-form__input">

<!-- `button` element in the `search-form` block-->
<button class="search-form__button">Search</button>

可选

元素对于block是可选的,不是所有blocks都有元素。

例子
<!-- `search-form` block -->
<div class="search-form">
    <!-- `input` block -->
    <input class="input">

    <!-- `button` block -->
    <button class="button">Search</button>
</div>

我该创建块还是元素?

创建块

如果一段代码可能被重用,并且不依赖页面的其他页面组件独立呈现。

创建元素

如果一段代码不能在没有父实体(块)的情况下单独使用)。

例外是必须分为较小部分(子元素)的元素,以简化开发。 在BEM方法中,您不能创建元素的元素。 在这种情况下,您不需要创建一个元素,而是创建一个服务块。

Modifier

定义块或元素的外观,状态或行为。

特点:

  • 修饰符名称描述其外观(“什么大小”或“哪个主题”等等 - size_s或theme_islands),其状态(“与其他人有什么不同?” - 禁用,重点关注等)及其 行为(“它如何行为?”或“如何响应用户?” - 如directions_left-top)。
  • 修饰符名称通过单个下划线(_)与块或元素名称分隔开。

修饰器的种类

布尔型

  • 仅当修饰符的存在或不存在是重要的时才使用,其值是无关紧要的。 例如,disabled。 如果存在布尔修饰符,则假定其值为true。
  • 修饰符的全名的结构遵循以下模式:
    • block-name_modifier-name
    • block-name__element-name_modifier-name
例子
<!-- The `search-form` block has the `focused` Boolean modifier -->
<form class="search-form search-form_focused">
    <input class="search-form__input">

    <!-- The `button` element has the `disabled` Boolean modifier -->
    <button class="search-form__button search-form__button_disabled">Search</button>
</form>

键-值型

  • 当修饰符值很重要时使用。 例如,“岛相关主题的menu”:menu_theme_islands。
  • 修饰符的全名的结构遵循以下模式:
    • block-name_modifier-name_modifier-value
    • block-name__element-name_modifier-name_modifier-value
例子
<!-- The `search-form` block has the `theme` modifier with the value `islands` -->
<form class="search-form search-form_theme_islands">
    <input class="search-form__input">

    <!-- The `button` element has the `size` modifier with the value `m` -->
    <button class="search-form__button search-form__button_size_m">Search</button>
</form>

<!-- You can't use two identical modifiers with different values simultaneously -->
<form class="search-form
            search-form_theme_islands
            search-form_theme_lite">

    <input class="search-form__input">

    <button class="search-form__button
                search-form__button_size_s
                search-form__button_size_m">
        Search
    </button>
</form>

修饰器使用指南

修饰器不能单独使用

以BEM的观点来看,修改器不能与所修改的块或元素隔离使用。 修饰符应该更改实体的外观,行为或状态,而不是替换它。

例子
<!--
    Correct. The `search-form` block has the `theme` modifier with
    the value `islands`
-->
<form class="search-form search-form_theme_islands">
    <input class="search-form__input">

    <button class="search-form__button">Search</button>
</form>

<!-- Incorrect. The modified class `search-form` is missing -->
<form class="search-form_theme_islands">
    <input class="search-form__input">

    <button class="search-form__button">Search</button>
</form>

混用

一个DOM节点定义多个BEM类的一种技术

例子
<!-- `header` block -->
<div class="header">
    <!--
        The `search-form` block is mixed with the `search-form` element
        from the `header` block
    -->
    <div class="search-form header__search-form"></div>
</div>

在这个例子中,我们结合了作为块的search-form和作为元素的header__search-form的样式以及行为。这种方式让我们在元素header__search-form中定义外部的几何关系和位置信息,同时块search-form自身任然是通用的。结果是,我们可以在其他环境中使用块search-form,因为它不指定任何的padding。这是我们称它独立的原因。

如何切换至BEM-style CSS

将在一个项目中实施BEM原则:

  • 抛开DOM模型并学习创建块。
  • 不要使用ID选择器或标签选择器。
  • 最小化嵌套选择器的数量。
  • 遵照CSS类命名通用约定,以避免名称冲突,命名尽可能语义清晰。
  • 遵循blocks,elements和modifiers的方式。
  • 如果块的CSS属性易于修改,将它们应用为修饰符。
  • 将代码合理切分成小的独立部件,以方便使用各个块。
  • 复用block。

翻译自https://en.bem.info/methodology/quick-start/