【译】BEM CSS命名规范一 Quick start

BEM 是对 CSS 命名的一种规范,推崇将 WEB 页面模块化,从而提高代码的重用度,减少后期维护的成本。原文

快速开始

简介

BEM(Block,Element,Modifier)是一个基于组件方式的 web 开发方法。
  他的基本思想是将用户界面分为独立的模块。
  即使是一个复杂的 UI 界面,也会使得用户界面开发简单而迅速,,并且允许重用现有的代码,而不是复制粘贴。

内容

  • 模块
  • 元素
  • 我应该创建一个 Block 还是一个 Element
  • 修饰符
  • 混合模式
  • 文件系统

模块

一个可重复使用的功能独立的页面组件。在 HTML 中,blocks 通过 class 属性表示。
特征:

  • 模块名称描述了它的目的(“它是什么?” —— 菜单或者按钮),而不是它的状态(“它看起来是什么样子?” —— 红色或者大的)。

例如:

<!-- 正确的,这个 'error' 模块是具有语义上的意义的 -->
<div class="error"></div>
<!-- 不正确的,它描述了模块的外观 -->
<div class="red-text"></div>
  • 模块不应该影响它所在的环境,这意味着你不应该为模块设置会影响到外部的形状(影响大小的 padding 或边框)和定位
  • 你也不应该在使用 BEM 的时候使用 CSS 标签选择器和 ID 选择器

这些保证了模块必要的独立性,可以更好地重用模块或者将他们从一个地方移动到另一个地方。

模块使用指南

嵌套关系

  • 模块与模块之间可以彼此嵌套
  • 你可以有任意级别的嵌套层次

例子:

<!-- 'head' 模块 -->
<header class="header">
    <!-- 嵌套 'logo' 模块 -->
    <div class="logo"></div>

    <!-- 嵌套 'search-form' 模块 -->
    <form class="search-form"></form>
</header>

元素

是一个模块的组成部分,且不能脱离模块单独地被使用。

特征:

  • 元素名称描述了它的目的(用处)(“这是什么?” —— item,text,等等。),而不是它的状态(“什么类型的,或者它看起来是什么样的?” —— 红色,大的,等等。)
  • 完整的元素名的结构是 block-name__element-name。元素的名字与模块的名字使用双下划线分隔(__)

例子:

<!-- 'search-form' 模块 -->
<form class="search-form">
    <!-- 在 'search-form' 模块内的 'input' 元素 -->
    <input class="search-form__input"/>
    <!-- 在 'search-form' 模块内的 'button' 元素 -->
    <button class="search-form__button"></button>
</form>

元素使用指南

  • 嵌套关系
  • 组成部分
  • 可选性

嵌套关系

  • 元素之间可以彼此嵌套
  • 你可以拥有任意层次的嵌套级别
  • 一个元素总是一个模块的一部分,而不是另一个元素的一部分,这意味着元素的名称不能被定义为 block__elem1__elem2 这样的层次结构。

例子:

<!--
     正确的。完整的元素名的结构符合如下模式:
     'block-name__element-name'
 -->
<form class="search-form">
    <div class="search-form__content">
        <input class="search-form__input"/>
        <button class="search-form__button"></button>
    </div>
</form>

 <!--
     不正确的。完整的元素名的结构不符合如下模式:
     'block-name__element-name'
 -->
<form class="search-form">
    <div class="search-form__content">
        <!-- 推荐:'search-form__input' 或者 'search-form__content-input' -->
        <input class="search-form__content__input"/>
        <!-- 推荐:'search-form__button' 或者 'search-form__content-button' -->
        <button class="search-form__content__button"></button>
    </div>
</form>

如果在模块名称上定义了命名空间,也要保证元素名称是依赖于模块的(block_elem)。
  在 DOM 树中,一个模块可以有元素嵌套结构:
例子

<div class="block">
    <div class="block_elem1">
        <div class="block_elem2">
            <div class="block_elem3"></div>
        </div>
    </div>
</div>

然而,在 BEM 的方法论中,这样的模块结构通常表示为一个并列的元素列表:
例子

.block {}
.block_elem1 {}
.block_elem2 {}
.block_elem3 {}

这样在代码中,你可以在不改变每个单独的元素的情况下改变一个模块的 DOM 结构:
例子

<div class="block">
    <div class="block_elem1">
        <div class="block_elem1"></div>
    </div>
    <div class="block_elem3"></div>
</div>

模块的结构改变了,但是元素的规则和他们的名字仍然保持不变。

组成部分

一个元素总是一个模块的一部分,你不应该单独使用它。
例子

<!-- 正确的。元素都位于 'search-form' 模块内 -->
<!-- 'search-form' 模块 -->
<form class="search-form">
    <!-- 在 'search-form' 模块内的 'input' 元素 -->
    <input class="search-form__input" />
    <!-- 在 'search-form' 模块内的 'button' 元素 -->
    <button class="search-form__button"></button>
</form>

<!-- 不正确的。元素位于 'search-form' 模块的上下文之外 -->
<!-- 'search-form' 模块 -->
<form class=""search-block>
</form>

<!-- 在 'search-form' 模块内的 'input' 元素 -->
<input class="search-form__input"/>

<!-- 在 'search-form' 模块内的 'button' 元素 -->
<button class="search-form__button"></button>

可选性

一个元素是一个可选的模块组件。并不是所有的模块都必须有元素。
例子:

<!-- 'search-form' 模块 -->
<div class="search-form">
    <!-- 'input' 模块 -->
    <input class="input"/>

    <!-- 'button' 模块 -->
    <button class="button"></button>
</div>

我应该创建一个模块还是一个元素?

  1. 如果这段代码可能被重用,并且它不依赖于页面上的其他组件,那你应该创建一个模块。
  2. 如果这段代码在没有父实体(模块)的情况下不能使用,那你应该创建一个元素。

为了简化开发,元素应该被分割成一小部分-子元素。在 BEM 方法论中,你不能创建元素的元素,在这种情况下,你需要创建一个服务模块,而不是创建一个元素。

修饰符

一种用于定义模块和元素的外观,状态和行为的实体。
特征:

  • 修饰符的名称描述了它的外观(“多大?”或者“它的主题是什么?”等等—— size_s 或者 theme_islands),它的状态(“它与其他有什么不同?” —— disabledfocused,等等)以及他的行为(“它的行为什么?”或者“它如何响应用户?”——比如 directions_left-top)。
  • 修饰符的名字与模块或者元素的名字使用单下划线分隔(_)

修饰符的类型

Boolean

  • 当修饰符的存在或不存在是重要的,与它的值无关时使用这种类型的修饰符。比如:disabled。如果一个布尔类型的修饰符是可见的,它的值被假定为 true
  • 修饰符的全名的结构遵循如下模式:
    • block-name_modifier_name
    • block-name__element-name_modifier-name

例子

<!-- 'search-form' 模块有一个 ‘focused’ 的布尔类型的修饰符 -->
<form class="search-form search-form_focused">
    <input class="search-form__input"/>

    <!-- 'button' 元素有一个 'disabled' 的布尔类型修饰符 -->
    <button class="search-form__button search-form__button_disabled">Search</button>
</form>

键-值

  • 当修饰符的值是重要的使用键值对类型。例如:“一个 islands 设计主题的按钮”:menu_theme_islands
  • 这种类型的修饰符的全名的结构遵循如下模式:
    • block-name_modifier-name_modifier-value
    • block-name__element-name_modifier-name_modifier-value

例子

<!-- The `search-form` 模块有值为 'islands' 的 `theme` 修饰 -->
<form class="search-form search-form_theme_islands">
    <input class="search-form__input">

    <!-- The `button` 元素有值为 'm' 的 `size` 修饰 -->
    <button class="search-form__button search-form__button_size_m">Search</button>
</form>

<!-- 你不能同时使用两个具有不同值的的相同修饰符 -->
<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 的角度,一个修饰符不能脱离模块或元素而被使用。一个修饰符应该改变实体的外观,行为或者状态,而不是替换它。
例子

<!-- 正确的。'search-form' 模块有值为 'islands' 的 'theme' 修饰符 -->
<form class="search-form search-form_theme_islands">
    <input class="search-form__input">

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

<!-- 不正确的。'search-form' 丢失了 -->
<form class="search-form_theme_islands">
    <input class="search-form__input">

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

[为什么需要在元素或修饰符的名称上添写上模块的名称?](Why write the block name in the names of modifiers and elements?)

混合模式

一种在单一的 DOM 节点上使用不同 BEM 实体的技术。
混合模式允许你:

  • 结合多个实体的行为和样式,而不是重复编写代码
  • 在现有代码的基础上创建具有新语义的 UI 组件

例子:

<!-- 'header' 模块 -->
<div class="header">
    <!--
        将 'header' 模块的 'search-form' 元素与 'search-form' 模块混合在一起使用
    -->
    <div class="search-form header__search-form"></div>
</div>

在这个例子中,我们将 header 模块的 search-form 元素与 search-form 模块的行为和样式结合在一起。这种方式允许我们在 header__search-form 元素上设置额外的形状和定位,而 search-form 模块仍然是通用的。因此,我们可以在任何环境中使用模块,因为模块没有指定任何填充。这正是我们可以独立调用模块的原因。

文件系统

在 BEM 方法论中采用的组件概念同样适用于项目的文件结构中。模块、元素和修饰符的实现可以被分在独立的文件中,这意味着,我们单独地使用它们。
特征:

  • 一个单独的模块对应一个单独地目录
  • 模块和其对应的目录拥有相同的名字。比如, header 模块放置在 header/ 目录中,menu 模块放置在 menu/ 目录中。
  • 一个模块的实现分为单独的文件。比如, header.cssheader.js
  • 模块目录是其元素和修饰所在目录的根目录。
  • 元素目录的名称以双下划线(__)开始。比如,header/__logo/ 和 menu/__item
  • 修饰目录的名称以单下划线(_)开始。比如,header_fixedmenu/_theme_islands/
  • 元素和修饰的实现分为不同的文件。比如,header__input.jsheader_theme_islands.css

例子:

search-form/                           # Directory of the search-form

    __input/                           # Subdirectory of the search-form__input
        search-form__input.css         # CSS implementation of the
                                       # search-form__input element
        search-form__input.js          # JavaScript implementation of the
                                       # search-form__input element

    __button/                          # Subdirectory of the search-form__button element
        search-form__button.css
        search-form__button.js

    _theme/                            # Subdirectory of the search-form_theme modifier
        search-form_theme_islands.css  # CSS implementation of the search-form block
                                       # that has the theme modifier with the value
                                       # islands
        search-form_theme_lite.css     # CSS implementation of the search-form block
                                       # that has the theme modifier with the value
                                       # lite

search-form.css                        # CSS implementation of the search-form block
search-form.js                         # JavaScript implementation of the
                                       # search-form block

这样的文件结构可以很好地支持我们重用代码。

在生产环境中,这些分支的文件结构将会被组合成共享的文件。

遵循这样的文件结构并不是必须的。你可以使用任何可替代的项目结构,根据 BEM 原则来组织你的文件结构,比如:

自己英文水平有限,如果文中有错误,或者歧异,或者不恰当的地方,希望大家提出来,非常愿意接受大家的批评与建议。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容