# 特指度和层叠 Specificity and the Cascade

# 特指度

选择符的特指度由选择符本身的组成部分决定。一个特指度值由四部分组成,比如 0, 0, 0, 0 。

特指度是从左向右比较的。

  • 选择符中每个 ID 选择符,加 0, 1, 0, 0
  • 每个类选择符,属性选择符,伪类,加 0, 0, 1, 0
  • 每个元素选择符,伪元素,加 0, 0, 0, 1
  • 连接符和通用选择符不增加特指度。

例如:

h1 {
  color: red;
} /* specificity = 0,0,0,1 */
p em {
  color: purple;
} /* specificity = 0,0,0,2 */
.grape {
  color: purple;
} /* specificity = 0,0,1,0 */
*.bright {
  color: yellow;
} /* specificity = 0,0,1,0 */
p.bright em.dark {
  color: maroon;
} /* specificity = 0,0,2,2 */
#id216 {
  color: blue;
} /* specificity = 0,1,0,0 */
div#sidebar *[href] {
  color: silver;
} /* specificity = 0,1,1,1 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 声明和特指度

h1 {
  color: silver;
  background: black;
}
1
2
3
4

浏览器执行时会将它打散为单独的规则:

h1 {
  color: silver;
}
h1 {
  background: black;
}
1
2
3
4
5
6

多个选择符作用于同一个元素上时,不同属性均会生效,相同的属性依据特指度高者生效。

# 通用选择符的特指度

通用选择符不增加特指度,特指度为 0,0,0,0 。但它与没有特指度是不同的。

div p {} /* 0,0,0,2 */

body * strong {} /* 0,0,0,2 */
1
2
3

# ID 和属性选择符的特指度

ID选择符合属性选择符使用id时是有区别的

#meadow {
  color: green;
} /* 0,1,0,0 */

*[id='meadow'] {
  color: red;
} /* 0,0,1,0 */


html > body table tr[id='totals'] td ul > li {
  color: maroon;
} /* 0,0,1,7 */

li#answer {
  color: navy;
} /* 0,1,0,1 (胜出) */

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 行内样式的特指度

行内样式声明的特指度比其他声明都高。特指度为 1, 0, 0, 0

# 重要声明 !important

有时某个声明非常重要,超过其他所有声明,称为重要声明(important declarations)。

在声明末尾的分号之前加上 !important 即可:

p.dark {
  color: #333 !important; /* 选中元素的的此属性超过其他一切声明 */
  background: white;
}
1
2
3
4

# 继承

继承指设定的样式不仅作用在选中元素上,还作用到其所有后代身上。

很多属性不会继承,比如多数盒模型的属性,包括 margin padding background border 等。

继承的值没有特指度,连 0 都没有。所以 0 特指度的 通用选择符会战胜 没有特指度的继承样式。

# 层叠

如果特指度完全相同,则后声明的覆盖先声明的样式。

如果一个样式表中,样式和 头部的 @import 的样式冲突,则当前样式表中的生效,引入的样式都算在引入的位置,当前样式表中的样式位置算在它的后面声明。

正因为前后位置有影响,所以通常才推荐按照一定的顺序编写链接的样式。

a:link {
  color: blue;
}
a:visited {
  color: purple;
}
a:focus {
  color: green;
}
a:hover {
  color: red;
}
a:active {
  color: orange;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

因为以上选择符的特指度相等,都是 0, 0, 1, 0。所以最后匹配的会生效。

试想,点击(active)的时候,如果 a:active 没有写在最后,则会被它后面的样式覆盖。

如果按照以下顺序设置链接样式:

a:active {
  color: orange;
}
a:focus {
  color: green;
}
a:hover {
  color: red;
}
a:link {
  color: blue;
}
a:visited {
  color: purple;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

a:activea:focusa:hover 永远都不会生效,因为 a:linka:visited 在它们后面,一个链接要么已访问,要么是未访问,a:linka:visited 总有一个会覆盖前面的样式。

当然,以上的所有冲突只会发生在设置相同的属性的时候,设置不同的属性则不会被影响。还有就是 :link:visited 样式的顺序并不重要,因为未访问和已访问是不会同时被匹配到的。

把伪类串在一起可以消除这一系列的问题:

a:link {
  color: blue;
}
a:visited {
  color: purple;
}
a:link:hover {
  color: red;
}
a:visited:hover {
  color: gray;
}
1
2
3
4
5
6
7
8
9
10
11
12

以上样式任意调换顺序都不会有影响。

但是,加上 :active 状态后,顺序又变得重要了:

a:link {
  color: blue;
}
a:visited {
  color: purple;
}
a:link:hover {
  color: red;
}
a:visited:hover {
  color: gray;
}
a:link:active {
  color: orange;
}
a:visited:active {
  color: silver;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

如果把上述的 :active 移到 :hover 之前,那么 :active 将会被忽略。

解决办法就是增加串联的伪类数量

a:link {
  color: blue;
}
a:visited {
  color: purple;
}

a:link:hover:active {
  color: orange;
} /* 特指度增加,不会被 hover 取代 */
a:visited:hover:active {
  color: silver;
} /* 特指度增加,不会被 hover 取代 */

a:link:hover {
  color: red;
}
a:visited:hover {
  color: gray;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20