[关闭]
@GaoyuanHfut 2017-08-02T14:09:07.000000Z 字数 4346 阅读 595

BEM组件开发规范


4.1 BEM是什么

BEM的意思就是块(block)、元素(element)、修饰符(modifier),是由Yandex团队提出的一种前端命名方法论。这种巧妙的命名方法让你的CSS类对其他开发者来说更加透明而且更有意义。BEM命名约定更加严格,而且包含更多的信息,它们用于一个团队开发一个耗时的大项目。
elementUI采用 BEM 风格来写 CSS,这样的好处是类名基本都是一级,少数才会有嵌套情况,这样很容易的就可以直接覆盖掉原有样式。[bem的用法与好处][5].

4.2 生成一个Block

BEM中的Block一个块是一个独立的实体,就像应用的一块“积木”。一个块既可以是简单的也可以是复合的(包含其他块)。

块的名称是描述了它的用途(“它是什么?” menu或button),而不是它的状态(“它是什么样子的?” red或big)。

<!-- 正确的做法.  `error` block 说明了块的意义 -->
<div class="error"></div>

<!-- 错误的做法. "red-text"只描述了他的表面 -->
<div class="red-text"></div>

块可以互相嵌套:

<!-- `header` 块 -->
<header class="header">
    <!-- 嵌套的 `logo` 块 -->
    <div class="logo"></div>

    <!-- 嵌套的 `search-form` 块 -->
    <form class="search-form"></form>
</header>

使用@component block-name{...}就可以生成一个Block。
例如搜索表单就是一个块。
添加下面的代码就可以创建一个search-form的Block:

@component search-form {
    padding: 0;
    margin: 0;
}
编译出来的代码如下:
.search-form {
    padding: 0;
    margin: 0;
}

4.3 生成一个Element

BEM中一个元素是块的一部分,具有某种功能。元素是依赖上下文的:它们只有处于他们应该属于的块的上下文中时才是有意义的。(这是它和block最大的区别,后面会提到)

element的名称是描述了它的用途(“它是什么?” item, text, etc.),而不是它的状态(“它是什么样子的?” red或big)。

例如一个输入域和一个按钮是Search块的中的元素。

可以使用@descendent element-name{...}嵌套在Block中,创建一个Element。

你可像下面的代码一样,创建一个名为text-field的Element:

@component search-form {
    padding: 0;
    margin: 0;

    @descendent text-field {
        border: 1px solid #ccc;
    }

}

编译之后,你就能看到一个新的Element就创建了,以”__”连接表示:

.search-form {
    padding: 0;
    margin: 0;
}

.search-form__text-field {
    border: 1px solid #ccc;
}

嵌套

元素可以相互嵌套且可以有任意数量的嵌套层数。

元素总是一个块的一部分,而不是另一个元素的子元素。那意味着不允许定义block__elem1__elem2这样的元素.(element中使用了,但我们为了使代码更清晰,不允许这样写)

<!--
    正确的做法. 元素名称的结构遵循下面的结构:
    `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>

<!--
    错误的做法,没有遵守以下结构:
    `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">Search</button>
    </div>
</form>

block的内部允许element 互相嵌套(建议尽量不要这样写)

<div class="block">
    <div class="block__elem1">
        <div class="block__elem2">
            <div class="block__elem3"></div>
        </div>
    </div>
</div>

填充物和可选项

元素始终是块的一部分,不应该单独使用它,但不是所有的块都有元素。

4.4 是该创建个block还是element?

选择block
如果一段代码可以重用,且不依赖于正在执行的其他页面组件。
选择element
如果没有父元素(block)则不能单独使用的代码.

开发中如果遇到元素必须要分成更小的部分–子元素–。在这种情况下,您不应该创建一个element,而是需要创建一个block。

4.5 生成一个Modifier

尽管BEM允许给Block和Element创建一个Modifier,但postcss-salad插件只会处理嵌套在Block中的Modifier,而不会创建嵌套在Element的Modifier。可以通过@modifier name{...}语法,将Modifier嵌套在它的父块中。

可以像下面的代码一样,给search-form添加一个advanced的Modifier:

@component search-form {
    padding: 0;
    margin: 0;

    @modifier advanced {
        padding: 1rem;
    }

    @descendent text-field {
        border: 1px solid #ccc;
    }

}
编译出来的代码如下:
.search-form {
    padding: 0;
    margin: 0;
}

.search-form--advanced {
    padding: 1rem;
}

.search-form__text-field {
    border: 1px solid #ccc;
}

4.6 生成一个State

通过@when name {...}语法嵌套在一个组件(Component)或一个Descendent中可以创建一个State。

在textField添加一个invalid,给textField的Descendent添加一个名为invalid的State:

@component SearchForm {
    padding: 0;
    margin: 0;

    @modifier advanced {
        padding: 1rem;
    }

    @descendent textField {
        border: 1px solid #ccc;

        /* This creates a state for the textField descendant */
        @when invalid {
            border: 1px solid red;
        }
    }

}

编译出来的代码会包括一个名为invalid的State:

.SearchForm {
    padding: 0;
    margin: 0;
}

.SearchForm--advanced {
    padding: 1rem;
}

.SearchForm__textField {
    border: 1px solid #ccc;
}

.SearchForm-textField.is-invalid {
    border: 1px solid red;
}

4.7 组件全名空间

通过@component-namespace name {...}可以给组件(Components)创建命名空间,而且Descendents,Modifiers和States都嵌套在里面。如果你喜欢,整个样式表都可以采用命名空间,而且可以自动添加到类的前面。

使用@component-namespace mine{...}给容器添加一个命名空间:

@component-namespace mine {
        @component SearchForm {
            padding: 0;
            margin: 0;
            @modifier advanced {
                padding: 1rem;
            }
                @descendent textField {
                border: 1px solid #ccc;

                @when invalid {
                    border: 1px solid red;
                }
            }
            }
        }

编译出来的代码,会在你的组件前添加一个mine-前缀。如:

.mine-SearchForm {
    padding: 0;
    margin: 0;
}
.mine-SearchForm--advanced {
    padding: 1rem;
}
.mine-SearchForm-textField {
    border: 1px solid #ccc;
}
.mine-SearchForm-textField.is-invalid {
    border: 1px solid red;
}

4.8 简化下写法

下面是postcss-salad的配置文件:

  "shortcuts": {//简化写法
    "component": "b",//@b=@component
    "modifier": "m",//@m=@ modifier
    "descendent": "e"//@e=@ descendent

 解释下descendent是element的另一种说法
      },
      "separators": {//编译规则
        "descendent": "__",
        "modifier": "--"
      }

分别用@b ,@e,@m作为component, modifier, descendent的简写.编译成dist中的css时词与词之间的连接符为__或--来区分bem.
以btton为例:

@component-namespace el {
    @b button {//button作为一个block
    @m primary {//primary带有的样式 }
    @e header {//作为元素的样式}
    }
}

编译后的得到:

el-button{//button的基本样式}
el-button--primary {//主要的button按钮除了基本样式之外primary带有的样式 }
el-button__header{//头部元素的样式}
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注