why?
无论选择了什么样的css组织方法,你都会从更加结构化的css 和 Ui 结构中获益。有些方式不那么严格,更加灵活。而另一些方法则更加易于理解,适用于团队协作。
为什么要选择bem呢?它不像其他语法(smacss)那么复杂,但是仍然可以提供给我们优良的代码结构和易于识别的术语。
模块化
block永远不依赖于页面上的其他元素,因此不会遇到级联问题。而且易于从旧项目中迁移。只要从某一个块级元素开始即可。
可复用
以不同的方式组合独立的块级元素,重用它们,减少可维护的代码量。甚至可以构造一个基于block的库。
结构
bem法让css代码有良好的组织结构,既简单,又易于理解。
what?
概念
-
b – block
一个本身就是有意义的独立实体。尽管一个block可以和其他block嵌套和共同发挥作用,但语义上所有blocks是平等的,并没有等级或者优先级之分。没有表现为DOM的整体实体(例如控制器或模型)也可以是块。块名称可以包含拉丁字母,数字和短划线。
任何有class name的dom节点都可以成为block。
在一页中,没有对其他Blocks、elements的依赖。
e.g: header, container, menu, checkbox, input
-
e – element
Block的一部分,没有独立的意义,而且在语义上依附于Block存在。
e.g: menu item, list item, checkbox caption, header title元素名称可以包含拉丁字母,数字,短划线和下划线。主要是以两个下划线接在block之后,来表示从属关系。
在一个block下的任何dom节点都可以是element。
没有对同一页上其他blocks/elements的依赖。
// 好例子 .block__elem { color: #fff; } //坏例子 .block .block__elem { color: #042; } div.block__elem { color: #042; }
-
m – modifier
修饰符,一个block或者element上的flag,体现了外观或者行为的变化。修饰符名称可能包含拉丁字母,数字,短划线和下划线。以两个短划线接在element/block的类名之后,诸如
.block--mod
,.block__elem--mod
,.block--color-black
,block--color-red
。在复杂修饰符中的空格用短划线来代替。e.g: disabled, highlighted, checked, fixed, size big, bg yellow
修饰符是您添加到块/元素DOM节点的额外类名。仅将修饰符类添加到它们修改的块/元素,并保留原始类名。是添加不是替换。
<!-- 好例子 --> <div class="block block--mod">...</div> <div class="block block--size-big block--shadow-yes">...</div> <!-- 坏例子 --> <div class="block--mod">...</div>
在block层级的修饰符下的元素,可以这么写
.block--mod .block__elem {}
例子:
<form class="form form--theme-xmas form--simple"> <input class="form__input" type="text" /> <input class="form__submit form__submit--disabled" type="submit" /> </form>
.form { } .form--theme-xmas { } .form--simple { } .form__input { } .form__submit { } .form__submit--disabled { }
例子
如上图,可以在按钮上应用任何想要的标签,如Button,a, div 等,可使用block--modifier-value
语法。
.button {
display: inline-block;
border-radius: 3px;
padding: 7px 12px;
border: 1px solid #D5D5D5;
background-image: linear-gradient(#EEE, #DDD);
font: 700 13px/18px Helvetica, arial;
}
.button--state-success {
color: #FFF;
background: #569E3D linear-gradient(#79D858, #569E3D) repeat-x;
border-color: #4A993E;
}
.button--state-danger {
color: #900;
}
faq:
- 为什么要选择bem作为css模块化的解决方案?
精髓在于 块的独立性。
如果仅谈论CSS模块化解决方案,BEM的关键特性是块的独立性。 遵循CSS建议可以将块放入页面上的任何位置,并确保它不会受到周围环境的影响。 此外,如果您最近需要将另一个块嵌套到当前块中,则可以保证它们完全兼容。 换句话说,在维护Web应用程序时,您可以在页面中移动块,添加其他块并组合它们。
BEM CSS明确地定义了哪个CSS属于一个界面,因此使用它可以回答诸如“我可以删除这段代码吗?” 和“如果我改变这段代码,会发生什么以及哪些接口部分会受到影响?”的问题。
- 为什么要使用block–modifier,而不是将modifier直接和Block同时作用于一个元素上?
也就是说,为什么要避免使用menu__item button active
?
-
- 因为同一个dom节点可以既是Block,又是element,所以需要确认一个修饰符是基于block的还是基于element的。如果写成
<div class="menu__item button active"></div>
,就无法区分menu__itme.active
还是button.active
了。而加上前缀后,button--active
则明确地指出了active仅仅影响的是按钮。
- 因为同一个dom节点可以既是Block,又是element,所以需要确认一个修饰符是基于block的还是基于element的。如果写成
-
- 另一点是CSS的优先级。组合的选择器比单一的类选择器优先级更高。写的时候还要注意计算优先级的问题。但如果使用了前缀式的修饰符,就可以肯定层叠的选择器会Overwrite 修饰符。(这一点在应用了scoped后不用考虑)。
-
- 结构更加分明。比如
<div class="block block--mod">
,可以清晰地看到Block的结构。但<div class="block mod">
却不能起到同样的效果。当全局搜索block--mod
时,尤其会感谢这种实践方式。
- 结构更加分明。比如
- 如何命名修饰符?能否直接把它的css作为依据命名修饰符?
不能。首先,.block__element--border-bottom-5px
看上去奇丑无比,其次,在实践中,如果把5px改成了6px,那么还要连带选择器的名一起改,麻烦。而且,不能保证修饰符会永远只拥有某一个CSS属性,而且永远拥有它。所以,尽量还是选择语义上有意义的名字来命名修饰符。
- 类似
block__elem1__elem2__elem3
的元素嵌套元素怎么命名选择器?
根据BEM方法,块结构应尽量平整,您需要反映块的嵌套DOM结构。所以,对元素嵌套元素,可以都摊平到块级之下的子元素。如:
<div class='block'>
<div class='block__elem1'>
<div class='block__elem2'>
<div class='block__elem3'></div>
<div class='block__elem4'></div>
</div>
</div>
</div>
css结构应该为:
.block {}
.block__elem1 {}
.block__elem2 {}
.block__elem3 {}
这样,每一个element都只依赖于外层的block,可以很轻松地在block内部迁移代码,如下所示。
<div class='block'>
<div class='block__elem1'>
<div class='block__elem2'></div>
</div>
<div class='block__elem3'></div>
<div class='block__elem4'></div>
</div>
【笔者言:】我对这一点有异议。假如block__elem2中是flex布局子元素elem3, elem4,那么在迁移在后者时,仍然需要改动其父级元素。建议根据具体情况灵活采用,必要时,可以把内部的element作为一个block,再进行新的嵌套。
- bem不支持全局的css重置吗?
BEM不会禁止使用css全局reset,但用BEM的方式重置会更有效。
BEM认为每一个块都是独立的,不依赖于global reset css存在,而且global reset通常是以tag作为选择器,这也违反了规则。相反,bem建议在每个块上进行重置。利用Mixin的方式,假设Menu__item 和 list__item都是li元素,则二者都需要引入li的重置代码。 您可能会担心具有相同重置规则的多个块将在结果代码中重复出现。 但这就是CSS优化器应该为您做的事情。 作为开发人员,您可以独立开发每个块,就好像同一页面上没有其他块一样。
.menu {
@include reset-list;
}
.menu__item {
@include reset-list-item;
}
/* ... */
.list {
@include reset-list;
}
.list__item {
@include reset-list-item;
}
另外,以这样的方式去reset 全局,还可以避免在引入第三方库的时候,reset代码和第三方库的代码起了冲突。
【笔者言:】这样做的坏处是增加了代码量,需要开发者控制每一个Block的样式,给每一个都加上mixin。从实践上来讲,我不反对全局加入css reset。