层叠、优先级和继承
层叠
层叠指的就是这一系列规则。
它决定了如何解决css样式规则冲突,是 CSS 语言的基础。
虽然有经验的开发人员对层叠有大体的了解,但是层叠里有些规则还是容易让人误解。
当声明冲突时,层叠会依据三种条件解决冲突:
- 样式表的来源:样式是从哪里来的,包括你的样式和浏览器默认样式等。
- 选择器优先级:哪些选择器比另一些选择器更重要。
- 源码顺序:样式在样式表里的声明顺序。
下图概括展示了规则的用法:
这些规则让浏览器以可预测的方式解决 CSS 样式规则的冲突。
样式表的来源
样式的来源主要分为2中:
- 书写的样式表,即作者样式表;
- 用户代理样式表,即浏览器默认样式;
用户代理样式表优先级低,你的样式会覆盖它们。
!important 声明
样式来源规则有一个例外:标记为重要( important)的声明。 如下所示, 在声明的后面、分号的前面加上!important,该声明就会被标记为重要的声明。
color: red !important;
标记了!important 的声明会被当作更高优先级的来源, 因此总体的优先级按照由高到低排列如下所示:
- 作者的!important
- 作者样式表
- 用户代理样式表
理解优先级
如果无法用来源解决冲突声明,浏览器会尝试检查它们的优先级。
理解优先级很重要。
不理解样式的来源照样可以写 CSS,因为 99%的网站样式是来自同样的源。但是如果不理解优先级,就会被坑得很惨。不幸的是,很少有人提及这个概念。
浏览器将优先级分为两部分: HTML 的行内样式和选择器的样式。
行内样式
如果用 HTML 的 style 属性写样式,这个声明只会作用于当前元素。实际上行内元素属于“带作用域的”声明,它会覆盖任何来自样式表或者<style>标签的样式。
行内样式没有选择器,因为它们直接作用于所在的元素。
为了在样式表里覆盖行内声明,需要为声明添加!important,这样能将它提升到一个更高优先级的来源。
但如果行内样式也被标记为!important,就无法覆盖它了。
最好是只在样式表内用!important。
选择器优先级
不同类型的选择器有不同的优先级。比如, ID 选择器比类选择器优先级更高。
实际上, ID选择器的优先级比拥有任意多个类的选择器都高。同理,类选择器的优先级比标签选择器(也称类型选择器)更高。
优先级的准确规则如下:
- 如果选择器的 ID 数量更多,则它会胜出(即它更明确)。
- 如果 ID 数量一致,那么拥有最多类的选择器胜出。
- 如果以上两次比较都一致,那么拥有最多标签名的选择器胜出。
说明:
伪类选择器(如:hover)和属性选择器(如[type="input"])与一个类选择器的优先级相同。
*通用选择器( )和组合器( >、 +、 ~)对优先级没有影响。
如果你在 CSS 里写了一个声明,但是没有生效,一般是因为被更高优先级的规则覆盖了。
很多时候开发人员使用 ID 选择器,却不知道它会创建更高的优先级,之后就很难覆盖它。
如果要覆盖一个 ID 选择器的样式,就必须要用另一个 ID 选择器。
优先级标记
一个常用的表示优先级的方式是用数值形式来标记,通常用逗号隔开每个数。
比如,“1,2,2”表示选择器由 1 个 ID、 2 个类、 2 个标签组成。优先级最高的 ID 列为第一位,紧接着是类,最后是标签。
选择器 | ID | 类 | 标签 | 标记 |
---|---|---|---|---|
html body header h1 | 0 | 0 | 4 | 0,0,4 |
body header.page-header h1 | 0 | 1 | 3 | 0,1,3 |
.page-header .title | 0 | 2 | 0 | 0,2,0 |
#page-title | 1 | 0 | 0 | 1,0,0 |
有时,人们还会用 4 个数的标记,其中将最重要的位置用 0 或 1 来表示,代表一个声明是否是用行内样式添加的。此时,行内样式的优先级为“1,0,0,0”。它会覆盖通过选择器添加的样式,比如优先级为“0,1,2,0”( 1 个 ID 和 2 个类)的选择器。
关于优先级的思考
优先级容易发展为一种“军备竞赛”。在大型项目中这一点尤为突出。
通常最好让优先级尽可能低,这样当需要覆盖一些样式时,才能有选择空间。
源码顺序
层叠的第三步,也是最后一步,是源码顺序。
如果两个声明的来源和优先级相同,其中一个声明在样式表中出现较晚,或者位于页面较晚引入的样式表中,则该声明胜出。
链接样式和源码顺序
你刚开始学习 CSS 时,或许就知道给链接加样式要按照一定的顺序书写选择器。这是因为源码顺序影响了层叠。
a:link {
color: blue;
text-decoration: none;
}
a:visited {
color: purple;
}
a:hover {
text-decoration: underline;
}
a:active {
color: red;
}
书写顺序之所以很重要,是因为层叠。
优先级相同时,后出现的样式会覆盖先出现的样式。
如果一个元素同时处于两个或者更多状态,最后一个状态就能覆盖其他状态。如果用户将鼠标悬停在一个访问过的链接上,悬停效果会生效。如果用户在鼠标悬停时激活了链接(即点击了它),激活的样式会生效。
层叠值
层叠值——作为层叠结果,应用到一个元素上的特定属性的值。
浏览器遵循三个步骤,即来源、优先级、源码顺序,来解析网页上每个元素的每个属性。如果一个声明在层叠中“胜出”,它就被称作一个层叠值。
元素的每个属性最多只有一个层叠值。
两条经验法则
处理层叠时有两条通用的经验法则。因为它们很有用:
在选择器中不要使用 ID。
就算只用一个 ID,也会大幅提升优先级。当需要覆盖这个选择器时,通常找不到另一个有意义的 ID,于是就会复制原来的选择器,然后加上另一个类,让它区别于想要覆盖的选择器。
不要使用!important。
它比 ID 更难覆盖,一旦用了它,想要覆盖原先的声明,就需要再加上一个!important,而且依然要处理优先级的问题。
这两条规则是很好的建议,但不必固守它们,因为也有例外。
继承
还有最后一种给元素添加样式的方式: 继承。
经常有人会把层叠跟继承混淆。
虽然两者相关,但是应该分别理解它们。
如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。
比如通常会给<bod\y>元素加上 font-family,里面的所有后代元素都会继承这个字体,就不必给页面的每个元素明确指定字体了。
但不是所有的属性都能被继承。
默认情况下,只有特定的一些属性能被继承,通常是我们希望被继承的那些。它们主要是跟文本相关的属性: color、 font、 font-family、 font-size、font-weight、 font-variant、 font-style、 line-height、 letter-spacing、 text-align、text-indent、 text-transform、 white-space 以及 word-spacing。
还有一些其他的属性也可以被继承,比如列表属性: list-style、 list-style-type、list-style-position 以及 list-style-image。
表格的边框属性 border-collapse 和border-spacing 也能被继承。注意,这些属性控制的是表格的边框行为,而不是常用于指定非表格元素边框的属性。(恐怕没人希望将一个<div>的边框传递到每一个后代元素。)以上为不完全枚举,但是已经很详尽了。
特殊值
有两个特殊值可以赋给任意属性,用于控制层叠: inherit 和 initial。
使用inherit关键字
有时,我们想用继承代替一个层叠值。这时候可以用 inherit 关键字。
可以用它来覆盖另一个值,这样该元素就会继承其父元素的值。
还可以使用 inherit 关键字强制继承一个通常不会被继承的属性,比如边框和内边距。
通常在实践中很少这么做,但是盒模型时,你会看到一个实际用例。
使用initial关键字
有时,你需要撤销作用于某个元素的样式。这可以用 initial 关键字来实现。
每一个 CSS属性都有初始(默认)值。
如果将 initial 值赋给某个属性,那么就会有效地将其重置为默认值,这种操作相当于硬复位了该值。
你可能已经习惯了使用 auto 来实现这种重置效果。实际上,用 width: auto 是一样的,因为 width 的默认值就是 auto。
但是要注意, auto 不是所有属性的默认值,对很多属性来说甚至不是合法的值。
比如border-width: auto 和 padding: auto 是非法的,因此不会生效。
可以花点时间研究一下这些属性的初始值,不过使用 initial 更简单。
说明:声明 display: initial 等价于 display: inline。不管应用于哪种类型的元素,它都不会等于 display: block。这是因为 initial 重置为属性的初始值,而不是元素的初始值。 inline 才是 display 属性的初始值。
简写属性
简写属性是用于同时给多个属性赋值的属性。
比如 font 是一个简写属性,可以用于设置多种字体属性。 它指定 了 font-style、 font-weight、 font-size、 font-height 以 及font-family。
简写属性会默默覆盖其他样式
大多数简写属性可以省略一些值,只指定我们关注的值。
但是要知道,这样做仍然会设置省略的值,即它们会被隐式地设置为初始值。这会默默覆盖在其他地方定义的样式。
比如,如果给网页标题使用简写属性 font 时,省略 font-weight,那么字体粗细就会被设置为 normal。
理解简写值的顺序
简写属性会尽量包容指定的属性值的顺序。
可以设置 border: 1px solid black 或者border: black 1px solid,两者都会生效。
这是因为浏览器知道宽度、颜色、边框样式分别对应什么类型的值。
但是有很多属性的值很模糊。
在这种情况下,值的顺序很关键。理解这些简写属性的顺序很重要。
上、右、下、左
当遇到像 margin、 padding 这样的属性,还有为元素的四条边分别指定值的边框属性时,开发者容易弄错这些简写属性的顺序。这些属性的值是按顺时针方向,从上边开始的。
记住顺序能少犯错误。它的记忆口诀是 TRouBLe: top(上)、 right(右)、 bottom(下)、 left(左)。
水平、垂直
还有一些属性只支持最多指定两个值,这些属性包括 background-position、 box-shadow、 text-shadow(虽然严格来讲它们并不是简写属性)。
这些属性值的顺序跟 padding 这种四值属性的顺序刚好相反。比如, padding: 1em 2em 先指定了垂直方向的上/下属性值,然后才是水平方向的右/左属性值,而 background-position: 25% 75%则先指定水平方向的右/左属性值,然后才是垂直方向的上/下属性值。
虽然看起来顺序相反的定义违背了直觉,原因却很简单:这两个值代表了一个笛卡儿网格。笛卡儿网格的测量值一般是按照 x, y(水平,垂直)的顺序来的。
标签:优先级,样式,深入,样式表,层叠,解析,选择器,CSS,属性 From: https://www.cnblogs.com/niehao/p/18175098技巧:如果属性需要指定从一个点出发的两个方向的值,就想想“笛卡儿网格”。
如果属性需要指定一个元素四个方向的值,就想想“时钟”。