层叠,优先级与继承
作为CSS中最基本的概念,它们控制着 CSS 如何应用于 HTML 以及应用时的优先顺序
一、冲突规则
css
.box{
background-color:red !important;
background-color:black;
background-color:pink;
}
对于上述代码,我们在实际开发中会发现background-color:black;
和background-color:pink;
这两条应该产生效果的样式并没有生效,这是因为创建了三个应用与于同一元素的规则;这就是一个简单的冲突
而层叠,优先级与继承则决定了处理冲突时的规则,也就是确定如何选择元素的最终样式
二、层叠
层叠是CSS的一个基本特征,是一个定义了如何合并来自多个源的属性值的算法
层叠计算就是为了挑选 CSS 声明来给 CSS 属性设置正确的值
2.1 哪些CSS实体会参与层叠计算
- 只有 CSS 声明,就是
属性名值对
- 直接的CSS声明
- 包含在大多数 @规则的 CSS 声明(
下一点有详细讲解
)
css
.box{
color:pink; /* 这是一条属性名值对,即一个CSS声明 */
}
2.2 CSS声明的来源
CSS 层叠算法期望通过挑选 CSS 声明来给 CSS 属性设置正确的值。CSS 声明可以有不同的来源
来源类型
- 用户代理样式
- 作者样式表
- 读者自定义样式表
源的关系
- 它们共同构成了网页最终呈现给用户的样式效果
- 尽管 CSS 样式会来自这些不同的源,但它们的作用范围是重叠的
- CSS层叠算法则负责协调这些不同来源的样式声明,为每个 CSS 属性设置正确的值
源的默认优先级
一般情况下,不同来源样式的优先级顺序从高到低为:
- 读者自定义样式表(带
!important
) - 作者样式表(带
!important
) - 读者自定义样式表(普通)
- 作者样式表(普通)
- 用户代理样式
2.2.1 用户代理样式
浏览器会有一个基本的样式表来给任何网页设置默认样式,即用户代理样式 在没有任何额外样式定义的情况下,一个简单的 HTML 页面中的段落会以
浏览器默认的字体和颜色显示
。
浏览器差异: 不同浏览器的用户代理样式存在差异
CSS reset表: 为了统一不同浏览器的默认样式,减轻开发成本,网页开发者通常会使用 CSS reset 样式表,例如:
css
* { margin:0;padding:0; }
这样可以避免不同浏览器对元素默认的内外边距设置不同而导致布局出现差异
2.2.2 作者样式表
网页的作者可以定义文档的样式,这是最常见的样式表。大多数情况下此类型样式表会定义多个,它们构成网站的视觉和体验,即主题
2.2.3 读者自定义样式表
读者自定义样式表则是读者根据个人需求对网页样式进行的个性化调整
例如:
- 在 Firefox 浏览器中,可以在
about:config
中找到userContent.css
文件修改font-size
属性以调整网页文本大小
2.3 层叠算法
层叠算法的判断主要基于三个关键因素:重要性、特殊性和源顺序
2.3.1 重要性 -- !important
重要性是层叠算法中一个较为特殊的判断因素; 属于层叠算法中用于打破常规优先级的一种机制。
!important声明
!important
声明会使对应的样式具有最高优先级 ,它超越了特殊性和源顺序的常规判断,直接改变了样式的应用规则
css
.box{
color:blue !important;
color:red;
}
/* 对于上述代码,!important会覆盖后续声明,超越了源顺序的判断 */
注意
- 由于!important标记的声明具有最高的优先级,它会破坏层叠的正常逻辑,使代码的可维护性变差
- 所以我们需要谨慎使用
正常声明
- 没有
!important
标记的声明,按照特殊性和源顺序来决定优先级
2.3.2 特殊性 -- 选择器权重
特殊性是根据选择器的类型 来计算的,不同类型的选择器具有不同的权重 特殊性的计算方式 (
选择器优先级算法
) 通常可以用四个数字来表示 (a,b,c,d
)
选择器权重
- 如果存在内联样式,那么
A = 1
, 否则A = 0
; B
的值等于ID选择器
出现的次数;C
的值等于类选择器
和属性选择器
和伪类
出现的总次数;D
的值等于标签选择器
和伪元素
出现的总次数 。
比较规则
- 从左往右依次进行比较 ,较大者胜出,如果相等,则继续往右移动一位进行比较
- 如果4位全部相等,则按照源顺序来决定优先级
2.3.3 源顺序 -- 后来居上
当重要性和特殊性都相同时,后面定义的样式会覆盖前面定义的样式
css
.box{
color:black;
color:pink;
}
/* 2,3行的声明重要性与特殊性相同,则根据源顺序选择3行声明 */
2.4 特殊的 @规则与层叠计算
2.4.1 什么是 @规则
- At 规则是一个CSS 语句,用来指示 CSS 如何运行
一般结构:@identifier (RULE);
- 如我们常见的 @media,@keyframes...
@规则参与层叠计算吗
- 在 CSS 中,
部分 @规则参与层叠计算,部分不参与
- 而对于参与的@规则,又分为
两种情况
:- 整体参与筛选但内部声明不参与
- 内部声明参与
2.4.2 完全不参与层叠计算的 @规则
这是因为这类@规则有特点的规则 ,它们的存在和处理方式与层叠机制无关
@charset规则
该规则用于告知浏览器该CSS文件的字符编码 它必须放在任何规则之前的CSS文件最顶部;根据CSS规范,只能出现一次
如果一个CSS文件中有多个@charset规则呢?,如下:
css
@charset "UTF - 8";
/* 此处省略一些CSS代码 */
@charset "ISO - 8859 - 1";
/* 此处省略一些CSS代码 */
对于上述情况,可能出现两种结果
- 只有第一个有效:浏览器通常只会识别第一个
@charset
规则,而忽略后面的规则 - 可能导致编码错误:比如,样式表中的字符实际是按照
ISO - 8859 - 1
编码保存的,但第一个@charset
规则指定了UTF - 8
编码,那么浏览器会以UTF - 8
编码来解析这些字符,就可能导致字符显示不正确
@import规则
该规则用于引入外部的CSS文件,通常放在CSS文件的开头部分
css
@import url("styles.css");
@import url("styles1.css");
- 它的作用是将另一个 CSS 文件的内容引入到当前文件中
- 多个
@import
规则只是按顺序引入不同的文件,不会相互层叠,因此不参与层叠计算
2.4.3 整体参与筛选但内部声明不参与层叠的 @规则
这类@规则定义了一些特殊的对象 ,如
字体、动画关键帧等
,它们作为一个整体被筛选和应用,而内部的声明不会像普通的 CSS 声明那样相互层叠
@font-face
改规则用于自定义字体
css
/* 定义 */
@font-face {
font-family: 'MyFont';
src: url('myfont.woff2') format('woff2');
}
/* 使用 */
.box {
font-family: 'MyFont';
}
- 浏览器会根据
@font - face
规则的整体定义来加载和使用字体 - 不同的
@font - face
规则不会合并它们的描述符,只会选择符合条件的规则来应用,所以其内部声明不参与层叠计算
整体参与层叠算法的情况
css
.box {
font-family: 'MyFont1';
font-family: 'MyFont2';
}
@keyframes
改规则用于定义CSS动画的关键帧
css
/* 定义 */
@keyframes move {
from {
left:0;
}
to {
left:10px;
}
}
/* 使用 */
.box{
animation:move 2s linear infinite;
}
@keyframes
规则定义了一个完整的动画序列,浏览器会选择一个特定规则来应用动画,不会将多个@keyframes
规则的关键帧混合在一起,所以关键帧的声明不参与层叠计算。
2.4.4 内部声明参与层叠计算的 @规则
这类@规则通常是条件性 的,用于根据不同的条件(如
媒体查询、特性检测等
)来应用样式,其内部的 CSS 声明会像普通的声明一样参与层叠计算
@media规则
改规则根据媒体特性(如屏幕宽度、设备类型等)来应用不同的样式
css
@media (min - width: 768px) { body { font - size: 18px; } } @media (max - width: 767px) { body { font - size: 16px; } }
- 当满足不同的媒体查询条件时,这些规则内部的声明会像普通的 CSS 声明一样进行层叠计算,最终确定应用的样式
@supports规则
该规则用于检测浏览器是否支持某个 CSS 特性
css
@supports (display: grid) { .container { display: grid; } } @supports not (display: grid) { .container { display: flex; } }
2.5 重置样式 -- all属性
all
属性是一个简写属性,它可以一次性重置元素的所有 CSS 属性
为什么需要all属性
- 当你的 css 对样式完成更改之后,也许会在某种情况下希望把他们还原到一个已知样式上,这可能发生在动画、主题修改之类的情形中
all属性的取值
- initial --- 将元素的所有属性重置为浏览器默认的初始值(用户代理样式表)
css
.box{
all:initial;
}
- inherit --- 让元素的所有属性继承其父元素的属性值
css
.parent{
color:blue;
}
.parent .child{
all:inherit;
}
-
unset --- 对于可继承的属性,使用继承的值;对于不可继承的属性,使用初始值
-
revert --- 如果有自定义样式表,则恢复到自定义样式表;如果没有用户自定义样式,那么就恢复到浏览器的默认样式
-
revert-player --- 将元素的所有属性恢复到当前层叠层中该属性的上一个值
- 层叠层是一个更高级的特性,建立在层叠与优先级的基本概念之上
二、优先级
2.1 什么是优先级?
- 优先级是CSS中的一个匹配规则
- 浏览器根据该规则来判断哪些属性值与一个元素最为相关并进行应用
- 优先级是基于不同种类选择器 组成的匹配规则 ,这是指:
对于同一个元素的不同种类选择器或声明语句,通过优先级的计算规则该元素应该采用哪些声明
- 优先级的核心原则:优先级高的样式会覆盖优先级低的样式
html
<div class="box" id="box"></div>
<style>
div{
color:pink;
}
.box{
color:black;
}
#box{
color:blue;
}
/* 这么多选择器,我们怎么确定div的样式呢? -- 优先级的工作 */
</style>
注意
- 当同一个元素有
多个声明
的时候,优先级才会有意义 - 当优先级与多个CSS声明中任意一个声明的优先级相等的时候,CSS 中
最后的那个声明
将会被应用到元素上
2.2 选择器类型
优先级由四种不同的选择器类型来计算,从高到低依次为:
2.2.1 内联样式(inline style)
直接写在HTML元素的style属性的样式
html
<p style="color:pink;"></p>
2.2.2 ID选择器
以#
开头通过元素ID选择元素
css
#id{
color:pink;
}
2.2.3 类选择器,属性选择器和伪类选择器
- 类选择器 -- 以
.
开头 通过元素的class选择
css
.class{
color:pink;
}
- 属性选择器 -- 方括号
[]
包裹 根据元素的属性或属性值选择元素
css
[type="text"]{
color:pink;
}
- 伪类选择器 -- 以
:
开头 选择处于特定状态的元素
css
a:hover{
color:pink;
}}
2.2.4 元素选择器和伪元素选择器
- 元素选择器 -- 直接使用元素名称
css
p{
color:pink;
}
- 伪元素选择器 -- 以
::
开头 选择元素的特定部分
css
.box::first-line{
color:pink;
}
2.3 优先级的计算规则
优先级由四种不同的选择器类型来计算,从高到低依次为: 内联样式 > ID选择器 > 类选择器,属性选择器和伪类选择器 > 元素选择器和伪元素选择器
2.3.1 基础计算方式
可以用 四个数字(a, b, c, d) 来表示一个选择器的优先级 分别对应内联样式、ID 选择器、类选择器等、元素选择器等的数量。
a. 内联样式 :a = 1, b = 0, c = 0, d = 0 b. ID 选择器 :每出现一个 ID 选择器,b 加 1 c. 类选择器、属性选择器和伪类选择器 :每出现一个,c 加 1 d. 元素选择器和伪元素选择器:每出现一个,d 加 1
比较两个选择器的优先级时,先比较 a,若 a 相同则比较 b,以此类推。
实例
- 对于第一点给出的问题,可以得到解答:
HTML
<div class="box" id="box"></div>
<style>
/* 优先级:(0,0,0,1) */
div{
color:pink;
}
/* 优先级:(0,0,1,0) */
.box{
color:black;
}
/* 优先级:(0,1,0,0) */
#box{
color:blue;
}
/* 这么多选择器,我们怎么确定div的样式呢?*/
/* 根据比较三个选择器的优先级,可以得出:color:blue; */
</style>
2.3.2 例外规则 :!important
当在一个样式声明中使用一个
!important
规则时,此声明将覆盖任何其他声明;虽然从技术上讲,!important
与优先级无关,但它与最终的结果直接相关
- 在层叠算法的重要性中,我们提到了
!important会打破特殊性和源顺序
这一点 - 实际上,这也说明了 !important规则 会改变优先级规则
- 加上
!important
的声明会优先于其他所有未使用!important
的声明 - 当然,两条相互冲突的带有
!important
规则的声明被应用到相同的元素上时,拥有更大优先级
的声明将会被采用
例如
css
.class{
color:pink !important;
}
#id{
color:black;
}
- 最终元素还是会应用加上
!important
的选择器样式声明
使用建议
- 一定 要优先考虑使用样式规则的优先级来解决问题而不是
!important
- 只有 在需要覆盖全站或外部 CSS 的特定页面中使用
!important
- 永远不要 在你的插件中使用
!important
- 永远不要 在全站范围的 CSS 代码中使用
!important
怎样覆盖 !important
- 添加一条 带
!important
的 CSS 规则,再给这个给选择器更高的优先级 - 添加一样选择器,把它的位置放在原有声明的后面(
最后定义一条规则必胜
)
三、继承
3.1 什么是继承?
在 CSS 里,继承是一种机制 ,借助它元素能够从其祖先元素 那里获取属性值 这一特性可以让代码
更简洁,减少重复的样式声明
祖先元素
html
<div class="outer">
<div class="inner"></div>
</div>
- outer是innner的祖先元素
默认继承/默认不继承
在CSS中,每个 CSS 属性定义的概述 都指出了这个属性是默认继承还是默认不继承的 ("Inherited":Yes/No"
)
- 对于可继承属性,没有指定值时的子元素会取父元素的同属性计算值
- 对于不可继承属性,子元素不会自动获取父元素设置的这些同属性计算值
css
/* 对于上面的HTML代码 */
.outer{
color:red;
width:100px;
}
.inner{
/* 当子元素没有显示声明color与width的值,它们默认取什么呢? */
}
3.2 可继承属性
某些 CSS 属性具备继承性,也就是说子元素会自动继承父元素设置的这些属性值。常见的可继承属性如下:
3.2.1 字体相关属性
- font-family (
字体族
) - font-size (
字体大小
) - font-weight (
字体粗细
) - font-style (
字体族
)
3.2.2 文本相关属性
- color (
文本颜色
) - text-align (
文本对齐方式
) - line-height (
行高
)
3.2.3 列表相关属性
- line-style-type (
列表项标记类型
) - line-style-position (
列表项标记位置
)
3.3 不可继承属性
还有部分 CSS 属性是不可继承的,子元素不会自动获取父元素设置的这些属性值。常见的不可继承属性有:
3.3.1 盒模型相关属性
- width (
宽度
) - height (
高度
) - margin (
外边距
) - padding (
内边距
) - border (
边框
)
3.3.2 背景相关属性
- background-color (
背景颜色
) - background-image (
背景图像
)
3.4 属性初始值
上面我们提到了默认继承和默认不继承属性的特点与具体类型, 那么现在出现一个问题:
父元素的属性来自哪里?对于不可继承属性,这些属性默认取值又是什么?
根元素
- 首先我们需要知道一个概念"根元素",它是整个文档树的起始点,也是
所有其他元素的父元素或者祖先元素
- 在 HTML 文档中,
<html>
元素是根元素 - 对于大部分属性,只有文档的根元素会
使用属性的初始值
,而其他元素会依据继承规则或者层叠规则
来确定属性值
属性的初始值
- 属性的初始值是由 CSS 规范定义的,这些初始值的定义是为了保证在不同浏览器和设备上有一个统一的基础样式表现。
- 比如
color
属性的初始值是black
,font-size
的初始值是medium
等
得出结论
- 对于具有继承性的属性,若子元素没有为这些属性显式声明值,它们会从父元素那里继承属性值。
- 因为根元素是所有其他元素的
祖先
,所以在中间元素没有重新赋值的情况下,子元素最终会继承根元素
上设置的属性值 - 对于默认不继承的属性,当元素没有被显式地设置该属性值时,元素使用的就是该属性的初始值。
3.5 强制继承
在某些情景,可能我们想要指定的元素属性强制继承自父元素或重置为初始值 这时就可能使用到三个关键字:initial关键字,inherit关键字,unset关键字
3.5.1 initial关键字
initial
关键字的作用是把属性值设置为该属性在 CSS规范 里定义的初始值
- 对于可继承属性 ,使用
initial
会让元素放弃继承父元素的属性值,转而使用属性的初始值 - 对于不可继承属性 ,
initial
同样会将属性值设定为初始值。
3.5.2 inherit关键字
inherit
关键字的主要作用是让元素强制继承其父元素的某个属性值,不管该属性在默认情况下是否具备继承性
- 对于可继承属性 ,
inherit
关键字会强化这种继承行为。即便可能存在其他因素干扰继承,也能确保元素继承父元素的属性值。 - 对于不可继承属性 ,
inherit
关键字可以打破常规,让元素继承父元素的该属性值
3.5.3 unset关键字
unset
关键字的行为取决于属性是否具有继承性
- 对于可继承属性,它会使用继承值
- 对于不可继承属性 ,它的效果等同于
initial
,也就是使用属性的初始值
3.6 继承的优先级
继承的属性值优先级是最低的。若你给元素直接设置了某个属性值,这个值会覆盖继承来的值。
3.7 继承的性能
减少渲染计算
- 对于具有继承性的属性,只需要计算一次父元素的属性值,从而节省了渲染时间和计算资源,提高了页面的渲染性能
精简代码
- 通过继承,我们可以在父元素上统一设置一些共有的样式属性,这样不仅使 CSS 代码更简洁易读,也减少了代码量,从而加快了浏览器下载和解析 CSS 文件的速度,间接提高了页面的加载性能
四、层叠,优先级与继承的关系
4.1 前文概括
根据前文的学习,我们可以总结出层叠,优先级与继承分别是什么
4.1.1 层叠
定义
- 层叠是CSS的核心规则,浏览器根据这些规则以确定元素最终的样式
4.1.2 优先级
定义
- 优先级决定了在层叠过程中,哪些 CSS 规则会优先应用于元素
4.1.3 继承
定义
- 继承是一种机制,借助它元素能够从其祖先元素那里获取属性值
4.2 三者关系
4.2.1 继承与优先级
继承的属性值优先级是最低的。如果元素同时有直接设置的属性值和通过继承得到的属性值,那么直接设置的值会覆盖继承来的值。
4.2.2 层叠与优先级
层叠过程中会根据优先级来决定最终应用的样式。当不同的 CSS 规则因为层叠而冲突,在重要性相同时,优先级高的规则会胜出。 可以说层叠算法中涉及了优先级算法
4.2.3 继承与层叠
继承是层叠的一个部分。在层叠的过程中,首先会考虑元素是否通过继承获得了某些属性值,然后再根据其他直接应用于该元素的样式规则以及它们的优先级来决定最终的样式。
4.3 总结
继承
为元素提供了默认的样式来源
层叠
负责合并和冲突解决
优先级
则在层叠过程中决定了不同规则的权重
它们相互配合,共同实现了 CSS 样式在网页上的精确呈现。