嵌套选择器规则

众所周知Sass是一种高效、可靠而又精确的工具,给了我们很多自由空间,让开发者减少使用CSS的一些痛苦,当然,这也意味着一种新的责任到来。

本文由大漠根据Mario Ricalde的《Nested selectors: the inception rule》一文所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://thesassway.com/beginner/the-inception-rule,以及作者相关信息。

——作者:Mario Ricalde

——译者:大漠

众所周知Sass是一种高效、可靠而又精确的工具,给了我们很多自由空间,让开发者减少使用CSS的一些痛苦,当然,这也意味着一种新的责任到来。

##问题所在

在CSS中,我们都知道所有代码都在一个“根级别”的选择器中,每个CSS的样式声明都写嵌套的话,那意客味需要写很多的代码。

今天我要带领大家进入到Sass的最基本原则中。这就是所谓的“开始规则(Inception rule)”。此规则可以帮助你避免一些常见错误(使用Sass的常见错误),不管是你Sass的初学者,还是中级或者高级Sass开发者。

就拿下面的代码为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.post {
border-radius: 3px;
background: #FFF8FF;
border: 1px solid #EFC6F3;
padding: 15px;
color: #333333;
}
.post .title, .post .alt-title {
color: #000000;
font-size:20px;
}
.post .alt-title {
border-bottom:1px solid #EFC6F3;
}

奇怪的是,你在使用CSS的时候,一旦你被卡住的时候,你会考虑加载其它的类名,如此一来,你的HTML就看不到明于,你是否在你的结构中同时加过五个类名呢?

<div class="post complete highlight rounded clearfix">...</div>

这难道就是你日常生活中所说的,面包和奶油我都要吗?其实我认为这样让我无法享受CSS开发的乐趣。然而,只要Sass进入你的生活中,你会发现这样使用CSS太过时了。

结合Sass使用很容易,但也很容易的错误使用它。

当你在工作中开始使用Sass的时候,第一个让你喜欢的特性就是“选择器嵌套”。如果能根据选择嵌套让你节省少敲键盘等事情,这将是一个很奇特事情。

我们来的看下面的一个示例,这就是Sass中的选择器的嵌套:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$border: 1px solid #EFC6F3;
.post {
border-radius: 3px;
background: #FFF8FF;
border: 1px solid $border;
padding: 15px;
color: #333333;
.title {
color: #000000;
font-size:20px;
}
.alt-title {
@extend .title;
border-bottom:1px solid $border;
}
}

上面的代码会输出相同的CSS。下面的代码就是Sass编译出来的CSS,所以你可以看看是如何转换成CSS的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.post {
border-radius: 3px;
background: #FFF8FF;
border: 1px solid 1px solid #efc6f3;
padding: 15px;
color: #333333;
}
.post .title, .post .alt-title {
color: #000000;
font-size: 20px;
}
.post .alt-title {
border-bottom: 1px solid 1px solid #efc6f3;
}

所以这些就像孩子玩他的玩具一样,我们开始使用他们的功能,认为是他们的“最大潜力”。但实际情况是什么时候应该这样调用,这又将是CSS选择器的一个噩梦。

##CSS选择器的噩梦

对于前端工程师来说,其噩梦就是样式臃肿,而且下DOM紧密耦合在一起,你修改有关于结构的内容就会影响破坏前端的呈现

让我们来看一个不怎么好的HTML结构:

<body>
      <div class="container">
        <div class="content">
              <div class="articles">
                <div class="post">
                      <div class="title">
                        <h1><a href="#">Hello World</a>
                      </div>
                      <div class="content">
                        <p></p>
                        <ul>
                              <li>...</li>
                        </ul>
                      </div>
                      <div class="author">
                        <a href="#" class="display"><img src="..." /></a>
                        <h4><a href="#">...</a></h4>
                        <p>
                              <a href="#">...</a>
                              <ul>
                                <li>...</li>
                              </ul>
                        </p>
                      </div>
                </div>
              </div>
        </div>
      </div>
</body>

因为Sass给你提供了这方面的功能,你可以让你的选择器嵌套在里面,你的代码封装在一起,避免了与其他样式的冲突问题。你可能发现在Sass中的代码类似于你的DOM结构的嵌套。(这是不好的一种想法)。

来看一段不合理的Sass代码,类似不好的HTML的DOM结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
body {
div.container {
div.content {
div.articles {
& > div.post {
div.title {
h1 {
a {
}
}
}
div.content {
p { ... }
ul {
li { ... }
}
}
div.author {
a.display {
img { ... }
}
h4 {
a { ... }
}
p {
a { ... }
}
ul {
li { ... }
}
}
}
}
}
}
}

这样都好,对吗?使用上面的选择器,你百分之百的可以预测到什么时候会发生什么?没有级联可以击败选择器的权重

有关于CSS选择器权重的相关知识,可以阅读@99早前根据Vitaly Friedman的《CSS Specificity: Things You Should Know 》所译的文章《你应该知道的一些事情——CSS权重》,文章中详细介绍了选择器权重相关知识。——@大漠

Sass编译之后,我们看到这样的一个结果,你会发现我们创建了一个极差劲的CSS。唉!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
body { ... }
body div.content div.container { ... }
body div.content div.container div.articles { ... }
body div.content div.container div.articles > div.post { ... }
body div.content div.container div.articles > div.post div.title { ... }
body div.content div.container div.articles > div.post div.title h1 { ... }
body div.content div.container div.articles > div.post div.title h1 a { ... }
body div.content div.container div.articles > div.post div.content { ... }
body div.content div.container div.articles > div.post div.content p { ... }
body div.content div.container div.articles > div.post div.content ul { ... }
body div.content div.container div.articles > div.post div.content ul li { ... }
body div.content div.container div.articles > div.post div.author { ... }
body div.content div.container div.articles > div.post div.author a.display { ... }
body div.content div.container div.articles > div.post div.author a.display img { ... }
body div.content div.container div.articles > div.post div.author h4 { ... }
body div.content div.container div.articles > div.post div.author h4 a { ... }
body div.content div.container div.articles > div.post div.author p { ... }
body div.content div.container div.articles > div.post div.author p a { ... }
body div.content div.container div.articles > div.post div.author ul { ... }
body div.content div.container div.articles > div.post div.author ul li { ... }

有很多原因可以证明,这完全是错误的,从渲染到文件的大小等都足以说明。试想想,这是加了多少的字节,文件大小直接受影响,或许你会保守的说:

嘿,电脑速度很快。互联网下载速度也比较快!——用户谁不喜欢前端工程师

但是,这并不是唯一的一个问题,你的样式非常类似于DOM结构,可维护就变成一个问题。

你的结构做任何的修改都需要告诉Sass,反之也是如此。这也意味着,样式和结构完全违背了“级联”的部分宗旨。也就是所说的“层叠样式表”。

如果你这样写,还不如回到当初的年代,把CSS直接写到HTML的结构中。(请不要这样做)。

##满足简单规则

为了防止你陷入这样的噩梦之中,我创建了一些简单的规则。到现在为止,这个规则虽然还不成文,但还是有蛮多人跟着使用。

这个规则就是:不要让你的嵌套层级超过四个层级

这也就意味着你不需要一味的模仿DOM结构中的任何一点。如果你发现你的嵌套的层级忆超过四层,那这将是一个危险的信号。当然,有时候你为了需要,而不得不这样做,但你不能像这样做得太多。

##让嵌套在四层或更少层级内

一旦你理解选择器的具体问题之后,你需要考虑的是如何让你的代码更通用,需要改善你的环境,对象和交互状态等。

###网站内容

如果你的结构没有类名或ID,那么你至少需要一个标签。很好的例子就是,像h1~h6ulp有一个默认的样式。

有可能在一些环境下,你需要覆盖一些样式,这时你可能要增加几个选择器。当涉及到网站内容上下文时,使用具有一定特色的选择。

###页面内容(布局、侧边栏宽度和高度)

如果你是写布局的样式(侧边栏和内容维度,也就是根据页面上下内容元素而有所不同),那么你讨论的将是在页面中的上下文。通常你需要两个级别的缩进来达到你需要的目的。但是请记住,你应该只指定样式,而不是对象自身。下一节我们将讨论对像。

下面的示例就是我想要说的意思:

1
2
3
4
.cart {
#sidebar { width: 150px; }
#content { width: 850px; }
}

###对象

一个元素就是一个对象,他有可能就是自身,也有可能带有子元素(或后代元素),通常使用一个类名或ID来定义这个对象。这也是你代码中常见的一种类型。对象可以是任何东西,应该被当作一个整体传到你的页面中。你也可以将对象作为一个基本样式,然后需要的时候使用页面内容来修改他。

下面是常用的一些元素当对象使用的示例:

1
2
3
4
5
6
7
8
9
#sideabr
#content
#footer
.blog-post
.comment
.widget
.logo
.user
.button

你通常会设置一个顶层的类来识别对象,并将其做为一个基本的选择器,在那你应该使用最普通的选择器来写样式:

1
2
3
4
5
ul.special-deal {
...
li {...}
a {...}
}

请注意,对象最多只能是四层嵌套。大多数时候你只写两到三层嵌套,至少要留一个层级给交互。

###交互状态

当你与对象有交互状态时,交互状态会包括什么。当你有交互的时候,你的对象层级嵌套有可能接近或超过四层。这是预期的,并且是可以接受的。

##切记

  • 聪明:想想编译器是如何创建你的代码,并问自己,它生成的代码是自己真正需要的CSS吗?我总是问自己,这种风格还有更简单的选择器来实现?
  • 灵巧:使用编译器为你提供的一切。例如,使用@extend指令或mixin。每一个都有其自身的意义。
  • 记录:如果添加一个声明会影响你全局的HTML标签,你应该留一个言,将其记录下来。当数周或数月后,你再看你的代码,你知道发生了什么。注释是你很好的朋友,如果你要嵌套articleasidesectionh3这样的,你最好有一个很好的理由。
  • 创意:有没有一种方法,在没有增加额外的类名能使HTML与CSS更好的一起工作呢?如果有,他不影响语义做到这一点。我的意思是使用相邻选择器或子选择器等等来实现。只有知道你Sass中嵌套的层级才知道你的CSS规则。
  • 适度:任何事情滥用都是不好的。有疑问时要用你的常识来判断。

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

如需转载,烦请注明出处:

英文出处:http://thesassway.com/beginner/the-inception-rule

中文译文:http://www.w3cplus.com/preprocessor/beginner/the-inception-rule.html