深入理解 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 ...
随机推荐
- tf.contrib.layers.xavier_initializer
https://blog.csdn.net/yinruiyang94/article/details/78354257xavier_initializer( uniform=True, seed=No ...
- 洛谷P1280 尼克的任务 题解 动态规划/最短路
作者:zifeiy 标签:动态规划.最短路 题目链接:https://www.luogu.org/problem/P1280 题目大意: 有k个任务分布在第1至n这n个时间点,第i个任务的于第 \(P ...
- java面向接口编程之制定标准和简单工厂模式
制定一个标准,让别人去实现或者说满足它! Eg: interface USB{//定义USB标准 void useUSB();//USB有使用USB的行为 } 简单工厂模式 构建一个工厂出来,在里面进 ...
- pip安装python包时报字符编码错
比如安装scikit-learn时报错: django ascii’ codec can’t encode character 原因是用户目录或用户名存在中文,ascii不能解码,解决办法是在Pyth ...
- 【图数据库】史上超全面的Neo4j使用指南
转自:https://cloud.tencent.com/developer/article/1336299 在这篇文章中: 第一章:介绍 Neo4j是什么 Neo4j的特点 Neo4j的优点 第二章 ...
- linux模块加载竞争
到目前, 我们的讨论已来到一个模块加载的重要方面: 竞争情况. 如果你在如何编写你的 初始化函数上不小心, 你可能造成威胁到整个系统的稳定的情形. 我们将在本书稍后讨论 竞争情况; 现在, 快速提几点 ...
- UPC个人训练赛第十五场(AtCoder Grand Contest 031)
传送门: [1]:AtCoder [2]:UPC比赛场 [3]:UPC补题场 参考资料 [1]:https://www.cnblogs.com/QLU-ACM/p/11191644.html B.Re ...
- 2018-3-31-C#-谁改了我的代码
title author date CreateTime categories C# 谁改了我的代码 lindexi 2018-3-31 21:15:3 +0800 2018-2-13 17:23:3 ...
- linux 使用 jiffies 计数器
这个计数器和来读取它的实用函数位于 <linux/jiffies.h>, 尽管你会常常只是包含 <linux/sched.h>, 它会自动地将 jiffies.h 拉进来. 不 ...
- vue-learning:29 - component - 组件三大API之三:slot
组件三大API之三: slot <slot>标签 v-slot指令 普通插槽 有默认值的插槽 具名插槽 作用域插槽 v-slot是Vue 2.6.0引入的一个新语法指令,目的是统一之前sl ...