译文:Nesting Your BEM?
原文链接:http://csswizardry.com/2016/11/nesting-your-bem/
在我开始这篇文章之前,我得说这不是一个建议或者是新的“练习指南”。这只是我自己的一些思想狂潮。
我是一个[<cite>BEM</cite>](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/)的拥护和支持者。并且已经持续了很多年。这是有点有趣的期待。当然, 它给我提供了很多的东西:
* **软封装** 这有助于减少命名冲突。
* **自定义的CSS** 这帮助我理解DOM节点彼此之间的关系。
* **目标的选择** 这有助于减少子树之间的冲突,并且避免捕获太多的节点。
* **管理方式的特殊性** 这是一个很大的亮点。
* **严格的实现规则** 这能够防止我使用给定上下文以外的classes。
除了最后一点只有一半是真的......
BEM告诉我们,一个class, 例如: `.widget__title`, 仅仅只能被用在`.widget`内。 但是这仅仅是通过了协议的规定。开发人员可能会把`.widget_title`放在`.model`之内,并且仍能正常工作。这是因为:
* 他们之前没有见过BEM,或者是不知道执行它的方法
* 他们很懒惰,并且发现———即使是不应该,但是他们可以重用`.modal`内的`.widget_title`样式的,然后这样能够提前5分钟完成工作
他们能够做到这一点,它也能为他们工作:东西仍旧能够正确显示。不会因此导致额外的错误,因为 BEM 仅仅是一个规定,并且规定需要一致的认同。
为了规避这一点,我们可以像下面这样地来写CSS:
```
.widget { }
.widget .widget__title { }
```
现在开发者不能在`.modal`内使用`.widget_title`,因为我们告诉了我们的CSS:`wideget_title`仅仅在我们把它放到`.widget`中才能起效。现在我们开始执行这些事情,它将防止滥用。
这里还有一个问题:嵌套
## CSS中的嵌套
在很长的一段时间内,我曾[<cite>积极主张</cite>](http://cssguidelin.es/#specificity)CSS中的嵌套是一件坏事情,因为:
* 增加了特性 (这些应该始终要管理好);
* 引入了对存储位置的依懒 (不灵活系统的一个标志);
* 减少了可移植性 (这意味着我们不能随意移动它);
* 增加了脆弱性 (嵌套意味着选择器出错的可能性增加了)。
总之, [<cite>保持你的CSS选择器的简短性</cite>](http://csswizardry.com/2012/05/keep-your-css-selectors-short/).
但是在使用了嵌套BEM的情况中,我们看到了嵌套给我们带来了实实在在的好处。但是我们要如何处理这些缺陷呢?
## 特异性
注意,通常情况下始终保持低特异性是很重要的。这完全正确,并且这是一个很好的建议。但是,这里和我们熟知的那些是有一点区别的。人们在说特异性应当在任何情况下都处理好的时候,真正的意思是,我们应当保持一致性,并且选择器之间的区别很小。
理论上来说(但是,亲爱的,请不要尝试这样做),一个项目的唯一选择器是ID选择器,这将很好地管理特异性:特异性普遍是高的,但至少所有都符合并且相等。
当我们在讨论如何处理好一致性的问题时:我们指的是它的[<meta>特异性图<meta>](http://csswizardry.com/2014/10/the-specificity-graph/)尽可能的平缓。
如果我们观察下面这一系列的CSS组件:
```
.nav-primary { }
.nav-primary__item { }
.nav-primary__link { }
.masthead { }
.masthead__media { }
.masthead__text { }
.masthead__title { }
.sub-content { }
.sub-content__title { }
.sub-content__title--featured { }
.sub-content__img { }
```
…我们发现,他们每个class之间有着完全相同的特异性。这是一个很漂亮的平缓特异性图:
<figure>![Graph showing low and flat specificity](http://p0.qhimg.com/t01298e8f9265d223bb.png)
<figcaption>[<cute>查看大图</cute>](http://csswizardry.com/wp-content/uploads/2016/11/graph-specificity-01.png)</figcaption>
</figure>
一旦我们像下面这样去嵌套这些classes:
```
.nav-primary { }
.nav-primary .nav-primary__item { }
.nav-primary .nav-primary__link { }
.masthead { }
.masthead .masthead__media { }
.masthead .masthead__text { }
.masthead .masthead__title { }
.sub-content { }
.sub-content .sub-content__title { }
.sub-content .sub-content__title--featured { }
.sub-content .sub-content__img { }
```
…我们看到的特异性图将会是这样的:
<figure>![Graph showing changes in specificity](http://p0.qhimg.com/t01afba20a956d400fc.png)
<figcaption>[<meta>查看大图</meta>](http://csswizardry.com/wp-content/uploads/2016/11/graph-specificity-02.png)</figcaption>
</figure>
哦,天啊! 峰值(Spikes)! 峰值正是我们想要避免的,因为他们代表着项目中非常接近的选择器之间的特异性的波动。
这里我们看了嵌套中特异性导致的一些缺陷(Here we are visualising the specificity downside to nesting.)我们能避开它吗?怎样做?
## 链接第一个class
如果我们要链接第一个class (the Block) 到它自身, 像这样:
```
.nav-primary.nav-primary { }
.nav-primary .nav-primary__item { }
.nav-primary .nav-primary__link { }
.masthead.masthead { }
.masthead .masthead__media { }
.masthead .masthead__text { }
.masthead .masthead__title { }
.sub-content.sub-content { }
.sub-content .sub-content__title { }
.sub-content .sub-content__title--featured { }
.sub-content .sub-content__img { }
```
…我们可以使其特异性地匹配所有无副作用的嵌套元素:
* 我们不需要知道这个Block在DOM中的位置,因此我们不会依据一些可能更改的位置而去增加它的特异性
* 我们并没有连接到另一个不同的或者是特定的元素或者类。这意味着Block类依旧非常轻便。
这种特异性的增加完全依据它自身,现在我们看到了这样的特异性图:
<figure>![Graph showing higher but still flat specificity](http://p0.qhimg.com/t01cecef3a98ac52bbf.png)
<figcaption>[<cute>查看大图</cute>](http://csswizardry.com/wp-content/uploads/2016/11/graph-specificity-03.png)</figcaption>
</figure>
比第一张图高,但是仍旧非常平缓。尽管我们我们的特异性是两级的高度,它仍旧被很好的掌控:我们选择器组件没有特殊的权重。
## 用Sass简化
为了使嵌套以及链接更加简化,我们可以使用预处理,在这里是Sass:
我们应当都熟悉如何在Sass中嵌套常规选择器:
```
.nav-primary {
.nav-primary__item { }
.nav-primary__link { }
}
```
这给我们带来了,正如我们所期待的:
```
.nav-primary { }
.nav-primary .nav-primary__item { }
.nav-primary .nav-primary__link { }
```
但是我们如何快速并且有效地将第一个class链接到他自身?像这样:
```
.nav-primary {
&#{&} { }
.nav-primary__item { }
.nav-primary__link { }
}
```
通过使用 `&#{&}`, 我们可以将当前的class链接到它自身。这意味着我们所有Block的样式(在这种情况下, `.nav-primary`) 都在这里:
```
.nav-primary {
&#{&} { /* Block styles */ }
}
```
[<cute>看一个关于Sassmeister的小例子</cute>](http://www.sassmeister.com/gist/a14e5b242ee6b20932dd44df0a3d215c)
## 实际结果
现在,我们的处境是事实上在强制地使用,并且主动地阻止选择器的起效——如果我们主动地将它们从DOM中正确的部分移出的话。这可以帮助我们在其他开发者并不知道BEM如何起效的环境下工作,或者是那些倾向于使劲折腾直到一切看上去正常的人。
我们也有一个管理所有classes(虽然是增加的)的特异性
### 缺陷
我们正在增加一些特异性,这通常正是我们应该永远努力去避免的。
## 用例
如果你想要尝试延伸这种技术,开始之前,这里有必要确认一些关键的用例。第一个展现在我脑中的是 网格系统(grid systems) 一次又一次地,我看见开发者们在`.grid`父类外尝试去使用`.grid__item`类。所以,如果我打算开始使用这种技术的话,我会从这里开始:
```
.grid.grid { }
.grid .grid__item { }
```
## 用还是不用?
我不是很确定,正如我在开头说的那样,这不是一项我非常推荐并且致力于推行的技术。我仅仅是想要提出它,给大家作为一个参考,尤其是对那些发现自己正处于一个,其他开发者都在轻易地滥用CSS的环境中的开发者。
但是,我想说的是:如果你已经嵌套了你的BEM,请返回,通过链接你的第一个class去拉平你的特异性图。
译文:Nesting Your BEM?的更多相关文章
- 和BEM的战斗:10个常见问题及如何避免
原文链接: https://segmentfault.com/a/1190000006135647 无论你是刚刚发现BEM或者已经是个中熟手(作为web术语来说),你可能已经意识到它是一种有用的方法. ...
- CSS命名规范——BEM思想(非常赞的规范)
人们问我最多的问题之一是在CSS类名中“--”和“__”是什么意思?它们的出现是源于BEM和Nicolas Gallagher... BEM的意思就是块(block).元素(element).修饰符( ...
- Google C++单元测试框架GoogleTest---AdvancedGuide(译文)下
因为AdvancedGuide文档太长,分上下两部分,本文档接googletest--AdvancedGuide(译文)上:Google C++单元测试框架GoogleTest---AdvancedG ...
- Atitit.css 规范 bem 项目中 CSS 的组织和管理
Atitit.css 规范 bem 项目中 CSS 的组织和管理 1. 什么是BEM?1 1.1. 块(Block)2 1.2. 元素(Element)2 1.3. BEM树(和DOM树类似).3 ...
- Google C++单元测试框架GoogleTest---AdvancedGuide(译文)上
本文是gtest高级测试指南的译文,由于文章太长,分上下两部分. 一.简介 本文档将向您展示更多的断言,以及如何构造复杂的失败消息,传播致命的故障,重用和加速您的测试夹具,并在您的测试使用各种标志. ...
- CSS 命名管理 之 BEM
好吧,将 BEM 简单的解释为 “Block-Element-Modifier“, 其实是个不负责任的做法.鬼知道 Block 是什么啊?所以,看了一些似懂非懂的中文解释之后,自己还是得去找些英文来读 ...
- [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:实现基本的CRUD功能
英文渣水平,大伙凑合着看吧…… 这是微软官方SignalR 2.0教程Getting Started with Entity Framework 6 Code First using MVC 5 系列 ...
- [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:排序、筛选和分页
这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第三篇:排序.筛选和分页 原文:Sort ...
- [渣译文] 使用 MVC 5 的 EF6 Code First 入门 系列:MVC程序中实体框架的连接恢复和命令拦截
这是微软官方教程Getting Started with Entity Framework 6 Code First using MVC 5 系列的翻译,这里是第四篇:MVC程序中实体框架的连接恢复和 ...
随机推荐
- 利用javascript、php和ajax实现计算器
计算器和ajax部分: <?php /** * Created by PhpStorm. * User: Administrator * Date: 16-9-2 * Time: 上午9:20 ...
- 默认选中ComboBox的某一项
如: 让它选中“统计今天”(控件Name为cobListTime) 方法: 1.cobListTime.Text = cobListTime.Items[0].ToString();//默认选中第一个 ...
- sql server 2008空间释放
今天一原来的同事打电话说他们两个表加起来1.2t(每个表都有三四十个字段,6亿条记录),创建了索引之后空间增长到了2.2t,然后没有执行成功.问题在于虽然没执行成功,可是空间没有释放,整个系统只有2. ...
- NYOJ 21 三个水杯
三个水杯 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子.三个水杯之间相互倒水,并且水杯没有 ...
- Android从零开始——Android开发环境的安装
Android开发环境的安装 1 IDE Android可以使用开发的IDE有Eclipse 或者 Android Studio.Android Studio还处于v 0.1.x版本,是early a ...
- 高性能文件缓存key-value存储—Memcached
1.高性能文件缓存key-value存储—Redis 2.ASP.NET HttpRuntime.Cache缓存类使用总结 备注:三篇博文结合阅读,简单理解并且使用,如果想深入学习,请多参考文章中给出 ...
- jquery对javascript事件的封装一览
描述 jquery javascript 鼠标点击某个对象 click() onclick 鼠标双击某个对象 dblclick() ondblclick 元素获得焦点 focus() onfocus ...
- CSS类选择器和ID选择器
CSS类选择器和ID选择器皆允许以一种独立于文档元素的方式来指定样式,同时二者皆区分大小写. 区别如下: 第一:在同一个页面内,不允许有相同名字的id对象出现,但是允许相同名字的class 第二:当页 ...
- 实战2--应用EL表达式显示投票结果
(1)编写index.jsp页面,用于收集投票信息 <%@ page language="java" pageEncoding="GBK"%> &l ...
- 【读书笔记】iOS-GCD-使用方法
代码: -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { dispatch_async(dispatch_get_gl ...