winar_阿进

用BEM写出更具有可维护性的CSS

原文链接: www.integralist.co.uk

介绍

这篇文章教你一种方法,能够写出更具有可维护性的CSS,他就是"BEM"。

更新: @necolas 在推特上写了一个令人深思的评论,我正在用一个改进了的BEM命名习惯(BEM是一个框架,采用他能够合理的给所有的类命名并且写出更具维护性的CSS). 所以我在这里做一个说明,以免引起不必要的麻烦。

BEM: Block, Element, Modifier

BEM 代表 "Block, Element, Modifier" ,他是一个虽然简单但是却极其高效的方法将不同的组件和插件分类(就像下面所展示的那样)。

在每一个被定义的下都有不同的元素,他由对象而组成。对于每一个元素(依据他在块内出现的位置),你还可以去修饰该元素的状态。

BEM和其他构建CSS的方法 (OOCSS/SMACSS)相比,在方法原则上有些相似,但是他们在不损失构建效果的前提下,大大简化了其规则。

理解BEM最好的方法就是看使用他的例子(见下一章节)。但是如果你想了解他的历史以及其概念的细节的可视化的信息,请参考其BEM官方网站。

举例

下面展示的是一个金钱计算器的小插件。当你输入金钱的总额(e.g. £2.12p)并点击'calculate'按钮后,你就会得到不同的转换过的不同货币的列表。

HTML结构是很简单的...

<section>
    <h1>Sterling Calculator</h1>
    <form action="process.php" method="post">
        <p>Please enter an amount: (e.g. 92p, £2.12)</p>
        <p>
            <input name="amount"> 
            <input type="submit" value="Calculate">
        </p>
    </form>
</section> 

接下来我们加入类名,以便后期方便的为该插件写样式,最后我会分别解释添加了什么,以及为什么这样添加......

<section class="widget">
    <h1 class="widget__header">Sterling Calculator</h1>
    <form class="widget__form" action="process.php" method="post">
        <p>Please enter an amount: (e.g. 92p, £2.12)</p>
        <p>
            <input name="amount" class="widget__input widget__input--amount"> 
            <input type="submit" value="Calculate" class="widget__input widget__input--submit">
        </p>
    </form>
</section>

我们首先确定了最顶级的<section>元素作为我们的'block'。这是包裹元素的顶层。我们为其添加了widget类,这也将成为我们这个对象/插件的命名空间(不管你想为他起什么名称)。

所有我们添加在这个'block'里元素的类的命名,都将在顶层widget的命名空间下。

当我们要为<form>元素添加样式,那么我们就给该元素添加widget__form类。双下划线可以使我们更容易的辨认出来该类是widget块的一部分。我们也可以看到<input>元素命名为widget__input类。

以下是元素样式的命名列表...

  • widget
  • widget__header
  • widget__form
  • widget__input

注意到在widget__input类下有两个类:widget__input--amountwidget__input--submit。他们是修饰符。代表着我们当前元素的状态。

让我们看一下我们哪里用到了这些规则。我们在两个<input>元素上使用了两个相同的类widget__input(因为他们都会有一些相同的结构和样式)。但是他们也都有一些轻微的不同,因此我们可以用修饰符去使用在其额外的样式。

修饰符用两个连字符(破折号)连接,像这样:block__element--modifier

最终,该部件的CSS代码如下所示...

.widget {
    background-color: #FC3;
}

.widget__header {
    color: #930;
    font-size: 3em;
    margin-bottom: 0.3em;
    text-shadow: #FFF 1px 1px 2px;
}

.widget__input {
    -webkit-border-radius: 5px;
       -moz-border-radius: 5px;
         -o-border-radius: 5px;
            border-radius: 5px;

    font-size: 0.9em;
    line-height: 1.3;
    padding: 0.4em 0.7em;
}

.widget__input--amount {
    border: 1px solid #930;
}

.widget__input--submit {
    background-color: #EEE;
    border: 0;
}

为什么最终BEM战胜了其他?

我在这几年内尝试过不同的方法来写CSS,他们写起来都是这样子的......

现在采用的是BEM。

我之所以采用BEM而不是其他技术,是基于这样的原因:他虽然不像其他的方法那样令人困惑(i.e. SMACSS),但任然向我们提供了我们所需要的(i.e. OOCSS),具有辨识性的架构方法。

对于我来说,仅仅OOCSS是不够的。他让开发者决定如何命名他们的对象。但是在大型的项目或者超过一名开发者使会使命名很混乱,因为开发者在命名规范上意识的缺乏,对于每一个类应该做什么而感到困惑。

就SMACSS来说:我认为在某些方面他过于结构化。当我第一次使用它的时候,我就觉得他是我一直寻找的解决方案,但最终都由于我在开始的时候不知道他CSS的碎片化,他太巨大了。

对某些人来说,这并不是一个解决方案,但对于我来说他们就像那个老的格言“不要让我思考”说的那样。如果我必须仔细的去想他是怎么工作的,或者我需要在哪里找代码,那么这种方法就是失败的。

但BEM成功了,因为他提供了一种好的面向对象的结构化的带有相似术语的方法,并且他也足够简单。

但就像任何工具一样,他也不能被滥用。最终都需要开发者的理解和总体的技巧。

简单化

正如我之前说的那样,我之所以使用BEM的一个原因就是因为他足够简单。

他的使用术语和其他的方法相比十分相似。比如说:基于结构化的CSS你会看到这些术语:

  • 对象
  • 模块
  • 插件
  • 组件

…注意这些术语虽然不同,但是他们都指向相同的事情。毫无疑问,对于有些人来说,一定是一团糟。

BEM是不同的,因为他的术语是基于他工作的环境的:HTML和CSS。我们都知道在CSS之中什么是一个“块”,这是基础的构建块(不是一语双关),人们在不同的使用场景中是知道怎么使用的。

有一天我看到这个代码块,他真的很可怕。

…在一个人的说话的语境中有一大串代码,“块”很简单,但又是很专注的一个词,在很多情况下他也很重要。

我们都知道,当我们和CSS的一起工作的时候,我们所指的是“元素”。别有别的词语更适合这个描述,因为这正是我们正在做的事情的最准确的描述。

最后,“修饰器”这个单词也是很简单的,但是对于不同的开发者来说,却有着不同的理解和相似性。

我想修饰下这个元素,我应该怎样做呢?

任然是结构化

但由于这个简单的/ 结构化的工具,我们需要去编写一个可维护性的容易理解的代码。BEM在工程中就是很合适的。

总结

我知道我之前说了关于SMACSS,(没错,就是他!),但是当我在第一次使用SMACSS的时候,我仍然感到了他的琐碎,“额,将这些东西搞在一起真的很头大,尽管他看起来运行良好.”。有了BEM之后,我就不再有这种担心了。我看到他只有最初的担心。我不喜欢用双下划线或者双破折号。但是现在我也很喜欢使用它们。

如果你想看更多的关于BEM的用法,向您推荐一个小的CSS抽象库,叫做inuit.css,它是由Harry Roberts 编写,也可以在我的网站上查看。