层叠、优先级和继承
TIP
❑ 组成层叠的四个部分
❑ 层叠和继承的区别
❑ 如何控制样式和元素的对应关系
❑ 简写声明的常见误区
层叠
当声明冲突时,层叠会依据三种条件解决冲突:
(1) 样式表的来源:作者样式 > 浏览器默认样式
(2) 选择器优先级:id 选择器 > 类选择器 > 标签选择器
(3) 源码顺序:样式在样式表里的声明顺序,优先级相同的情况下,采用“后来居上”原则
结论:
- 当声明之间有冲突时,看选择器的优先级:id 选择器 > 类选择器 > 标签选择器
- 作者样式的
!important
> 行内样式 - 行内样式的
!important
优先级最高,谁也无法覆盖
样式表的来源
1.用户代理样式
如果长期使用 CSS,你大概习惯了覆盖用户代理的样式。这种做法实际上就是利用了层叠的样式来源规则。你写的样式会覆盖用户代理样式,因为来源不同。
2.!important
声明
标记了 !important
的声明会被当作更高优先级的来源,因此总体的优先级按照由高到低排列如下所示:
(1) 作者的 !important
(2) 作者
(3) 用户代理
思考
作者的 !important
声明,是在跟谁竞争优先级呢?
理解优先级
不理解样式的来源照样可以写 CSS,因为 99% 的网站样式是来自同样的源。
浏览器将优先级分为两部分:HTML 的行内样式和选择器的样式。
1.行内样式
如果用 HTML 的 style
属性写样式,这个声明只会作用于当前元素。实际上行内元素属于“带作用域的”声明,它会覆盖任何来自样式表或者 <style>
标签的样式。行内样式没有选择器,因为它们直接作用于所在的元素。
为了在样式表里覆盖行内声明,需要为声明添加 !important
,这样能将它提升到一个更高优先级的来源。但如果行内样式也被标记为 !important
,就无法覆盖它了。
结论:
- 当声明之间有冲突时,看选择器的优先级:id 选择器 > 类选择器 > 标签选择器
- 作者样式的
!important
> 行内样式 - 行内样式的
!important
优先级最高,谁也无法覆盖
2.选择器优先级
优先级的准确规则如下:
❑ 如果选择器的 id 数量更多,则它会胜出(即它更明确)。
❑ 如果 id 数量一致,那么拥有最多类的选择器胜出。
❑ 如果以上两次比较都一致,那么拥有最多标签名的选择器胜出。
伪类选择器(如 :hover
)和属性选择器(如 [type="input"]
)与一个类选择器的优先级相同。通用选择器(*
)和组合器(>
、+
、~
)对优先级没有影响。
3.优先级标记
选择器 | 权重 |
---|---|
!important | 无穷大 |
行内样式 | 1,0,0,0 |
id 选择器 | 0,1,0,0 |
类、伪类、属性选择器 | 0,0,1,0 |
标签、伪元素选择器 | 0,0,0,1 |
通用选择器 * 、组合器(> 、~ 、+ )、否定伪类 :not 选择器 | 0,0,0,0 |
继承的样式 | 没有权值 |
通用选择器 *
,组合器(>
、~
、+
),否定伪类 :not
对优先级没有影响,不作计入。
:not
伪类不像其它伪类,它不会增加选择器的优先级。:not(X)
伪类的优先级即为它参数选择器 X
的优先级。
4.关于优先级的思考
通常最好让优先级尽可能低,这样当需要覆盖一些样式时,才能有选择空间。
源码顺序
1.链接样式和源码顺序
这个顺序的记忆口诀是“LoVe/HAte”(“爱/恨”),即 link(链接)、visited(访问)、hover(悬停)、active(激活)。
思考
以 Typora 的主题制作为例,写 CSS 样式代码时,应该遵循的源码顺序是什么?
How to organize CSS @ 9elements
The Definitive Guide to CSS Styling Order
High-level advice and guidelines for writing sane, manageable, scalable CSS
2.层叠值
浏览器遵循三个步骤,即来源、优先级、源码顺序,来解析网页上每个元素的每个属性。如果一个声明在层叠中“胜出”,它就被称作一个层叠值。元素的每个属性最多只有一个层叠值。
层叠值——作为层叠结果,应用到一个元素上的特定属性的值。
如果一个元素上始终没有指定一个属性,这个属性就没有层叠值。
框图总结
两条经验法则
(1) 在选择器中不要使用 id。就算只用一个 id,也会大幅提升优先级。当需要覆盖这个选择器时,通常找不到另一个有意义的 id,于是就会复制原来的选择器,然后加上另一个类,让它区别于想要覆盖的选择器。
(2) 不要使用 !important
。它比 id 更难覆盖,一旦用了它,想要覆盖原先的声明,就需要再加上一个 !important
,而且依然要处理优先级的问题。
继承
如果一个元素的某个属性没有显式设定,则可能会继承某个祖先元素的值。
支持继承的属性
字体系列属性
font-family
:字体系列font-weight
:字体的粗细font-size
:字体的大小font-style
:字体的风格文本系列属性
text-indent
:文本缩进text-align
:文本水平对齐line-height
:行高word-spacing
:单词之间的间距letter-spacing
:中文或者字母之间的间距text-transform
:控制文本大小写(就是uppercase
、lowercase
、capitalize
这三个)color
:文本颜色元素可见性
visibility
:控制元素显示隐藏列表布局属性
list-style
:列表风格,包括list-style-type
、list-style-image
等光标属性
cursor
:光标显示为何种形态
无继承的属性
display
:规定元素应该生成的框的类型文本属性:
vertical-align
:垂直文本对齐text-decoration
:规定添加到文本的装饰text-shadow
:文本阴影效果white-space
:空白符的处理unicode-bidi
:设置文本的方向盒子模型的属性:
width
、height
、margin
、border
、padding
背景属性:
background
、background-color
、background-image
、background-repeat
、background-position
、background-attachment
定位属性:
float
、clear
、position
、top
、right
、bottom
、left
、min-width
、min-height
、max-width
、max-height
、overflow
、clip
、z-index
生成内容属性:
content
、counter-reset
、counter-increment
轮廓样式属性:
outline-style
、outline-width
、outline-color
、outline
页面样式属性:
size
、page-break-before
、page-break-after
声音样式属性:
pause-before
、pause-after
、pause
、cue-before
、cue-after
、cue
、play-during
特殊值
有两个特殊值可以赋给任意属性,用于控制层叠:inherit
和 initial
。
通常我们会给网页的所有链接加上一个字体颜色(如果不加的话,就会以用户代理样式为准)。这个颜色也会作用于页脚的“Terms of use”链接。
示例 HTML 代码:
<footer class="footer">
© 2016 Wombat Coffee Roasters —
<a href="/terms-of-use">Terms of use</a>
</footer>
示例 CSS 代码:
.footer {
color: #666;
background-color: #ccc;
padding: 15px 0;
text-align: center;
font-size: 14px;
}
通过 F12 查看 .footer
内部的 a
元素,可以看到,用户代理样式的伪类 a:-webkit-any-link
,覆盖了作者样式的类选择器 .footer
。color
属性不是会继承吗,为什么 footer
里的 a
标签没有继承 footer
的灰色,仍然是蓝色的呢? 这是因为,虽然子元素有默认继承父元素样式的特点,但是默认继承的样式其优先级最低,通常会被用户代理样式覆盖。如果需要覆盖用户代理样式,可以通过关键字 inherit
显式指定继承父元素的样式。
继续向样式表中添加如下代码:
.footer {
color: #666;
background-color: #ccc;
padding: 15px 0;
text-align: center;
font-size: 14px;
}
.footer a {
color: inherit;
}
加入这段代码之后,显示使用 inherit
指定继承的样式就可以覆盖用户代理样式,此时“Terms of use”链接会变成灰色。
结论:显式使用 inherit
继承的样式(灰色) > 用户代理样式(蓝色) > 默认继承的样式(灰色)
简写属性
总结
❑ 控制选择器的优先级
❑ 不要混淆层叠和继承
❑ 某些属性会被继承,包括文本、列表、表格边框相关的属性
❑ 不要混淆 initial
和 auto
值
❑ 简写属性要注意 TRouBLe
的顺序,避免踩坑