深入理解 CSS(Cascading Style Sheets)中的层叠(Cascading)
标题中的 Cascading 亦可以理解为级联。
进入正文,这是一个很有意思的现象。可以直接跳到 总结一下 部分,看完再回过头来阅读本文。
引子
假设我们有如下结构:
<p class="txt" style="color:red">123456789</p>
上面的 p 标签只有一个内联 CSS,很明显,在没有其他样式的干预下,文本 .txt 的颜色肯定就是红色的。

如果此时,我们希望改变 .txt p 标签元素的内容文字的颜色,但是不能去修改内联 CSS,只能通过样式文件去实现,像是这样:
.txt {
color: green;
}
嗯。稍微对 CSS 有点了解的同学都会知道,上面的 CSS 文件设置的样式不会生效,因为内联样式比上述 CSS 中的样式优先级要更高。
上述这种说法不是很严谨,下文会细说。
OK,有同学就会说了,这简单,在 CSS 样式文件中添加 !important 后缀即可 。像是这样:
.txt {
color: green!important;
}
如此操作之后,文本的颜色确实变成了绿色,因为在 CSS 文件中带 !important 后缀的规则优先级大于内联样式中同个但不带 !important 的样式。

内联样式的 !important 与样式表中的 !important
问题来了。
如果在内联样式中,我们也给加上 !important 会怎么样呢?
<p class="txt" style="color:red!important">123456789</p>
.txt {
color: green!important;
}
此时,内联的 !important 优先级更高,文本表现为红色。
问题又来了,那如果此时我们无法修改内联样式,只能修改样式表,有办法能覆盖内掉内联的 !important 吗?
animtion 的威力(Chromium 内核)
哦吼,还真有一种看似是奇技淫巧,实则不是的方法。让我们康康:
<p class="txt" style="color:red!important">123456789</p>
我们给 .txt p 元素新增一个动画,改变它的颜色。
.txt {
animation: colorGreen 2s infinite;
}
@keyframes colorGreen {
0%,
100% {
color: green;
}
}
这里新增了一个无限循环的动画,且动画初始状态及结束状态都赋予 color: green。甚至,我们都没有在规则后缀添加 !important。
神奇的事情发生了,文本的颜色变成了绿色,成功的覆盖了内联的 <p class="txt" style="color:red!important"> 的红色样式。

CodePen Demo -- the priority of CSS Animation
常见 CSS 优先级误区
严格来说也不算是误区(错误),但是这种说法不够严谨。
通常我们聊到 CSS 规则的优先级,第一时间都会想到这个表,也就是给不同的 CSS 规则赋予不同的权重:
一个选择器的优先级可以说是由四个部分相加 (分量),可以认为是 个十百千 四位数的四个位数:
- 千位: 如果声明在 style 的属性(内联样式)则该位得一分。这样的声明没有选择器,所以它得分总是1000
- 百位: 选择器中包含ID选择器则该位得一分
- 十位: 选择器中包含类选择器、属性选择器或者伪类则该位得一分
- 个位:选择器中包含元素、伪元素选择器则该位得一分
总的来说是规则是:
内联 > id 选择器 > 类/属性/伪类选择器 > 标签元素/伪元素
上面的规则没有问题的。但是,注意,这里仅仅考虑的是页面作者定义的样式的优先级。首先,它并且没有包含 !important 规则。
其次,对于决定一个 CSS 样式的最终表现而言,还有非常重要的另外一个概念 -- 层叠。
Cascading -- 层叠
层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。它在CSS处于核心地位,CSS的全称层叠样式表正是强调了这一点。
那么什么所谓的多个源又表示什么呢?下面是影响层叠的五个源:
浏览器会有一个基本的样式表来给任何网页设置默认样式。这些样式统称用户代理样式
网页的作者可以定义文档的样式,这是最常见的样式表。大多数情况下此类型样式表会定义多个,它们构成网站的视觉和体验,即页面主题,可以理解为页面作者样式
读者,作为浏览器的用户,可以使用自定义样式表定制使用体验,可以理解为用户样式
动画(Animation),指使用 @Keyframes @规则定义状态间的动画,动画序列中定义关键帧的样式来控制CSS动画序列
过渡 (Transition)
CSS动画与层叠(重点)
CSS动画,指使用@Keyframes @规则定义状态间的动画。
这里有个重点:关键帧不参与层叠。
这意味着在任何时候 CSS 都是取单一的 @Keyframes 的值而不会是某几个@Keyframe的混合。同时仍应注意用 @Keyframes(@规则)定义的值会覆盖全部普通值,但会被 !important 的值覆盖
这里我其实没弄很明白,这里的意思就是动画过程中的每一帧,决定元素的样式表现只取决于单一的 @Keyframes 的值,但是规范和 MDN 文档中都明确表明,动画 @Keyframes 中的值仍会被 !important 规则覆盖,但是实际测试结果,在 Chromium 内核下,动画 @Keyframes 中的值层叠顺序高于 !important 规则。
CSS 选择器的层叠(级联)顺序
上面说的常见的优先级误区,仅仅是规定了网页的作者定义的样式的优先级。除此之外,CSS 优先级还需要考虑选择器的层叠(级联)顺序。
只有在层叠顺序相等时,使用哪个值才取决于样式的优先级。
根据 CSS Cascading 4 最新标准:
定义的当前规范下申明的层叠顺序优先级如下(越往下的优先级越高,下面的规则按升序排列):
- Normal user agent declarations
- Normal user declarations
- Normal author declarations
- Animation declarations
- Important author declarations
- Important user declarations
- Important user agent declarations
- Transition declarations
简单翻译一下:

按照上述算法,大概是这样:
过渡动画过程中每一帧的样式 > 用户代理、用户、页面作者设置的!important样式 > 动画过程中每一帧的样式优先级 > 页面作者、用户、用户代理普通样式
然而,经过多个浏览器的测试,实际上并不是这样。(尴尬了)
实际测试的结果
实际代码测试的结果得出的结论其实是与规范中的优先级不大一致的。
不同内核浏览器实际表现不大一致,
Chrome 78 / Safari 13.0.4 / Edge 44.18362 (与规范表现不一致,Chromium内核)
animation 动画样式 > 页面作者定义的 !important 样式 > transition 过渡动画中的样式 > 普通样式
Firefox 71.0 (与规范表现一致)
页面作者定义的 !important 样式 > animation 动画样式 > transition 过渡动画中的样式 > 普通样式
CodePen Demo -- the priority of CSS Animation
总结一下
上文其实很绕,看得人很晕。简单总结一下:
决定一个元素的样式的最终表现,除了需要比较页面作者定义的样式的优先级之外,还需要比较样式的层叠顺序;
层叠是 CSS 的一个基本特征,定义了如何合并来自多个源的属性值的算法,5 个决定 CSS 样式的源分别是:用户代理样式、页面作者样式、用户样式、动画、过渡;
只有在层叠顺序相等时,元素的最终样式使用哪个值才取决于样式的优先级;
最新规范中给出的层叠顺序优先级与实际测得的有出入,不同内核浏览器实际表现不一致。
更多详细的关于层叠和样式优先级的概念,你可以看看下面:
上述 MDN 的两份文档都是有中文版的,但是发现其中中文版有部分与英文版规范不一致,应该是后面英文版有更新,但是没有同步到中文版,遇到这种情况还是应该去读读规范,并且自己实际动手实验一下。
最后
上面的第四点是我自己实测所得,可能是我搞错了,或者是我理解错了,如果是我的错误希望大家帮忙指出,共同进步学习。
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
好了,本文到此结束,希望对你有帮助 :)
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
深入理解 CSS(Cascading Style Sheets)中的层叠(Cascading)的更多相关文章
- CSS层叠样式表(Cascading Style sheets)
CSS层叠样式表(Cascading Style sheets) --------- ---------------- ----------- --------------- ----------- ...
- How to include cascading style sheets (CSS) in JSF
In JSF 2.0, you can use <h:outputStylesheet /> output a css file. For example, <h:outputSty ...
- CSS( Cascading Style Sheets )简书
(注:带*号的属性是CSS3新增属性)一.基本规则1.css通常存储在样式表(style)中,用于定义如何显示HTML元素:2.css主要由两个部分构成:选择器和一条或多条声明. 选择器通常是需要改变 ...
- CSS media query应用中的层叠特性使用最佳实践
media query是css3规范中引入的,它提供了一种responsive design的基础机制:浏览器在不同size的设备中将以不同样式展现网页,这就给一个网页能够适应不同device一种可能 ...
- Qt Style Sheets帮助文档 Overview
Qt Style Sheets are a powerful mechanism that allows you to customize the appearance of widgets, in ...
- 深入理解CSS中的层叠上下文和层叠顺序(转)
by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=5115 零.世间的道 ...
- 深入理解css中的margin属性
深入理解css中的margin属性 之前我一直认为margin属性是一个非常简单的属性,但是最近做项目时遇到了一些问题,才发现margin属性还是有一些“坑”的,下面我会介绍margin的基本知识以及 ...
- 深入理解css中position属性及z-index属性
深入理解css中position属性及z-index属性 在网页设计中,position属性的使用是非常重要的.有时如果不能认识清楚这个属性,将会给我们带来很多意想不到的困难. position属性共 ...
- 深入理解CSS中的层叠上下文和层叠顺序
零.世间的道理都是想通的 在这个世界上,凡事都有个先后顺序,凡物都有个论资排辈.比方说食堂排队打饭,对吧,讲求先到先得,总不可能一拥而上.再比如说话语权,老婆的话永远是对的,领导的话永远是对的. 在C ...
随机推荐
- dotnet 设计规范 · 结构体定义
X 不要给结构体默认构造函数 默认的C#编译器也不让开发者定义有默认构造的结构体 X 不要定义易变的属性 易变的属性指的是在调用属性返回值的时候返回的是新的实例,易变的属性会有很多的问题. ✓ 需要确 ...
- Linux 查看iptables状态-重启
iptables 所在目录 : /etc/sysconfig/iptables # service iptables status #查看iptables状态 # service iptables r ...
- 【hdu 1112】The Proper Key
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...
- Sublime Text 安装中文、英文字体
在 Sublimte Text 如何使用默认的字体,英文好看,但是中文不好,所以我就找了一个支持中文英文的字体 YaHei Consolas Hybrid 这个字体看起来效果比较差 下载地址: 如果无 ...
- H3C 子网划分方法
- 看到两道小学数学题,实在是解不动,用js写了一下
把一个自然数的约数(除去它本身)按照从小到大的顺序写在它的左边,可以得到一个多位数,比如6的约数是1,2,3,写成一个多位数是1236,假如这个多位数中,没有直复数字,那么我们你这个多位数是唯一的.请 ...
- mysql报错:java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone.
mybatis链接mysql,启动服务报错: java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecogni ...
- Linux 内核提交和控制一个 urb
当驱动有数据发送到 USB 设备(如同在驱动的 write 函数中发生的), 一个 urb 必须被 分配来传送数据到设备. urb = usb_alloc_urb(0, GFP_KERNEL); if ...
- Python3使用Pyintaller-打包成exe
Pyinstaller打包exe执行文件 安装Pyinstaller 使用pip安装Pyinstaller 用管理员模式运行cmd,输入命令: pip install pyinstaller 此方法会 ...
- Java程序员必备:异常的十个关键知识点
前言 总结了Java异常十个关键知识点,面试或者工作中都有用哦,加油. 一. 异常是什么 异常是指阻止当前方法或作用域继续执行的问题.比如你读取的文件不存在,数组越界,进行除法时,除数为0等都会导致异 ...