标题中的 Cascading 亦可以理解为级联。

进入正文,这是一个很有意思的现象。可以直接跳到 总结一下 部分,看完再回过头来阅读本文。

引子

假设我们有如下结构:

  1. <p class="txt" style="color:red">123456789</p>

上面的 p 标签只有一个内联 CSS,很明显,在没有其他样式的干预下,文本 .txt 的颜色肯定就是红色的。

如果此时,我们希望改变 .txt p 标签元素的内容文字的颜色,但是不能去修改内联 CSS,只能通过样式文件去实现,像是这样:

  1. .txt {
  2. color: green;
  3. }

嗯。稍微对 CSS 有点了解的同学都会知道,上面的 CSS 文件设置的样式不会生效,因为内联样式比上述 CSS 中的样式优先级要更高。

上述这种说法不是很严谨,下文会细说。

OK,有同学就会说了,这简单,在 CSS 样式文件中添加 !important 后缀即可 。像是这样:

  1. .txt {
  2. color: green!important;
  3. }

如此操作之后,文本的颜色确实变成了绿色,因为在 CSS 文件中带 !important 后缀的规则优先级大于内联样式中同个但不带 !important 的样式。

内联样式的 !important 与样式表中的 !important

问题来了。

如果在内联样式中,我们也给加上 !important 会怎么样呢?

  1. <p class="txt" style="color:red!important">123456789</p> 
  1. .txt {
  2. color: green!important;
  3. }

此时,内联的 !important 优先级更高,文本表现为红色。

问题又来了,那如果此时我们无法修改内联样式,只能修改样式表,有办法能覆盖内掉内联的 !important 吗?

animtion 的威力(Chromium 内核)

哦吼,还真有一种看似是奇技淫巧,实则不是的方法。让我们康康:

  1. <p class="txt" style="color:red!important">123456789</p>

我们给 .txt p 元素新增一个动画,改变它的颜色。

  1. .txt {
  2. animation: colorGreen 2s infinite;
  3. }
  4.  
  5. @keyframes colorGreen {
  6. 0%,
  7. 100% {
  8. color: green;
  9. }
  10. }

这里新增了一个无限循环的动画,且动画初始状态及结束状态都赋予 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 最新标准:

CSS Cascading 4(Current Work)

定义的当前规范下申明的层叠顺序优先级如下(越往下的优先级越高,下面的规则按升序排列):

  • 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

总结一下

上文其实很绕,看得人很晕。简单总结一下:

  1. 决定一个元素的样式的最终表现,除了需要比较页面作者定义的样式的优先级之外,还需要比较样式的层叠顺序;

  2. 层叠是 CSS 的一个基本特征,定义了如何合并来自多个源的属性值的算法,5 个决定 CSS 样式的源分别是:用户代理样式、页面作者样式、用户样式、动画、过渡;

  3. 只有在层叠顺序相等时,元素的最终样式使用哪个值才取决于样式的优先级;

  4. 最新规范中给出的层叠顺序优先级与实际测得的有出入,不同内核浏览器实际表现不一致。

更多详细的关于层叠和样式优先级的概念,你可以看看下面:

上述 MDN 的两份文档都是有中文版的,但是发现其中中文版有部分与英文版规范不一致,应该是后面英文版有更新,但是没有同步到中文版,遇到这种情况还是应该去读读规范,并且自己实际动手实验一下。

最后

上面的第四点是我自己实测所得,可能是我搞错了,或者是我理解错了,如果是我的错误希望大家帮忙指出,共同进步学习。

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

好了,本文到此结束,希望对你有帮助 :)

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

深入理解 CSS(Cascading Style Sheets)中的层叠(Cascading)的更多相关文章

  1. CSS层叠样式表(Cascading Style sheets)

    CSS层叠样式表(Cascading Style sheets) --------- ---------------- ----------- --------------- ----------- ...

  2. 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 ...

  3. CSS( Cascading Style Sheets )简书

    (注:带*号的属性是CSS3新增属性)一.基本规则1.css通常存储在样式表(style)中,用于定义如何显示HTML元素:2.css主要由两个部分构成:选择器和一条或多条声明. 选择器通常是需要改变 ...

  4. CSS media query应用中的层叠特性使用最佳实践

    media query是css3规范中引入的,它提供了一种responsive design的基础机制:浏览器在不同size的设备中将以不同样式展现网页,这就给一个网页能够适应不同device一种可能 ...

  5. Qt Style Sheets帮助文档 Overview

    Qt Style Sheets are a powerful mechanism that allows you to customize the appearance of widgets, in ...

  6. 深入理解CSS中的层叠上下文和层叠顺序(转)

    by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=5115 零.世间的道 ...

  7. 深入理解css中的margin属性

    深入理解css中的margin属性 之前我一直认为margin属性是一个非常简单的属性,但是最近做项目时遇到了一些问题,才发现margin属性还是有一些“坑”的,下面我会介绍margin的基本知识以及 ...

  8. 深入理解css中position属性及z-index属性

    深入理解css中position属性及z-index属性 在网页设计中,position属性的使用是非常重要的.有时如果不能认识清楚这个属性,将会给我们带来很多意想不到的困难. position属性共 ...

  9. 深入理解CSS中的层叠上下文和层叠顺序

    零.世间的道理都是想通的 在这个世界上,凡事都有个先后顺序,凡物都有个论资排辈.比方说食堂排队打饭,对吧,讲求先到先得,总不可能一拥而上.再比如说话语权,老婆的话永远是对的,领导的话永远是对的. 在C ...

随机推荐

  1. iptables端口映射

    见上节透明代理设置 #iptables -t nat -A PREROUTING -i eth0 -p tcp -s 192.168.62.0/24 --dport 80 -j REDIRECT -- ...

  2. TP5 在模板读出Session值

    模板取值: <p class="info">后台登录中心{$Request.session.username}</p> 也可以 {$Think.sessio ...

  3. Python--day24--继承面试题

    输出:(打印的是Dog.func而不是Animal.func) __init__方法如果本生的类具有的话,父类的__init__方法就不在调用,没有才调用父类的__init__方法 派生属性: 如果既 ...

  4. Python--day41--条件

    1,条件 #锁 #acquire release#一个条件被创建之初 默认有一个False状态#False状态 会影响wait一直处于等待状态#notify(int数据类型) 造钥匙 代码示例:条件. ...

  5. 浅谈集合框架三、Map常用方法及常用工具类

    最近刚学完集合框架,想把自己的一些学习笔记与想法整理一下,所以本篇博客或许会有一些内容写的不严谨或者不正确,还请大神指出.初学者对于本篇博客只建议作为参考,欢迎留言共同学习. 之前有介绍集合框架的体系 ...

  6. 【b703】矩阵取数游戏

    Time Limit: 1 second Memory Limit: 50 MB [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规 ...

  7. PHP会员找回密码功能的简单实现

    文章来自:博客 http://www.jb51.net/article/91944.htm 设置思路 1.用户注册时需要提供一个E-MAIL邮箱,目的就是用该邮箱找回密码. 2.当用户忘记密码或用户名 ...

  8. webmagic笔记

    在class Spider中有run函数,调用了 processRequest(requestFinal)完成对页面的下载和处理.在这个函数里面先调用downloader.download(reque ...

  9. H3C RIP基本配置

  10. mysql 修改列为not null报错Invalid use of NULL value

    场景:mysql 给表新增parent_id列,并设置为not null,保存时报错Invalid use of NULL value. 报错原因:因为已存在的数据的parent_id列为null,与 ...