当有多个选择器作用在一个元素上时,哪个规则最终会应用到元素上?

其实这是通过层叠机制来控制的,这也和样式继承(元素从其父元素那里获得属性值)有关。

元素的最终样式可以在多个地方定义,它们以复杂的形式相互影响。这些复杂的相互作用使CSS变得非常强大,但也使其非常难于调试和理解。

层叠

CSS 是 Cascading Style Sheets 的缩写,这暗示层叠(cascade)的概念是很重要的。在最基本的层面上,它表明CSS规则的顺序很重要,但它比那更复杂。什么选择器在层叠中胜出取决于三个因素(这些都是按重量级顺序排列的——前面的的一种会否决后一种):

  1. 重要性(Importance)
  2. 专用性(Specificity)
  3. 源代码次序(Source order)

重要性

在CSS中,有一个特别的语法可以让一条规则总是优先于其他规则:!important。(常见于应用于iconfont图标属性后面)把它加在属性值的后面可以使这条声明有无比强大的力量。

让我们看一下这个例子:

  1. <p class="better">This is a paragraph.</p>
  2. <p class="better" id="winning">One selector to rule them all!</p>
  1. #winning {
  2. background-color: red;
  3. border: 1px solid black;
  4. }
  5. .better {
  6. background-color: gray;
  7. border: none !important;
  8. }
  9. p {
  10. background-color: blue;
  11. color: white;
  12. padding: 5px;
  13. }

这将生成以下:

让我们一起来看看发生了什么。

  1. 你可以看到第三条规则 colorpadding被运用了, 但 background-color没有,为什么?实际上,这三种情况都应该应用,因为在源顺序后面的规则通常会覆盖较早的规则。

  2. 然而, 在前面的规则被运用了,因为 IDs/class 选择器优先于element选择器。

  3. 这两个元素都有 class并带有 better属性, 但是第二个元素有 id 值为winning 。 因为比起class而言id专用性更高(在一个页面上id是唯一的, 但很多元素可以拥有相同的class — ID 选择器在它们的目标中是非常优先的),红色背景色和1pixel的黑色边框都应应用于第二元素,第一个元素获得灰色背景色,没有边框,如类所指定。

  4. 第二个元素获得红色背景色,但没有边框。为什么?因为 !important 在第二条规则中的声明——在 border: none之后写入它意味着尽管id具有更高的优先性,该声明也将优先于前面规则中的边界值声明。

注意: 重载这个 !important 声明的唯一方法是在后面的源码或者是一个拥有更高特殊性的源码中包含相同的 !important 特性的声明。

知道 !important存在是很有用的,这样当你在别人的代码中遇到它时,你就知道它是什么了。但是!我们建议你千万不要使用它,除非你绝对必须使用它。您可能不得不使用它的一种情况是,当您在CMS中工作时,您不能编辑核心的CSS模块,并且您确实想要重写一种不能以其他方式覆盖的样式。 但是,如果你能避免的话,不要使用它。由于 !important 改变了层叠正常工作的方式,因此调试CSS问题,尤其是在大型样式表中,会变得非常困难。

要注意一个CSS声明的重要性取决于它被指定在什么样式表内——用户可以设置自定义样式表覆盖开发商的样式,例如用户可能有视力障碍,想设置字体大小对所有网页的访问是双倍的正常大小,以便更容易阅读。

相互冲突的声明将按以下顺序适用,后一种将覆盖先前的声明

  1. 在用户代理样式表的声明 (例如:浏览器在没有其他声明的默认样式).
  2. 用户样式表中的普通声明(由用户设置的自定义样式)。
  3. 作者样式表中的普通声明(这是我们设置的样式,Web开发人员)。
  4. 作者样式表中的重要声明
  5. 用户样式表中的重要声明

Web开发者的样式表覆盖用户的样式表是合理的,所以设计可以保持预期,但是有时候用户有很好的理由来重写web开发人员样式,如上所述,这可以通过在用户的规则中使用!important

专用性

专用性基本上是衡量选择器的具体程度的一种方法——它能匹配多少元素。如上面所示的示例所示,元素选择器具有很低的专用性。类选择器具有更高的专用性,所以将战胜元素选择器。ID选择器有甚至更高的专用性, 所以将战胜类选择器. 战胜ID选择器的唯一方法是使用 !important

一个选择器具有的专用性的量是用四种不同的值(或组件)来衡量的,它们可以被认为是千位,百位,十位和个位——在四个列中的四个简单数字:

  1. 千位:如果声明是在style 属性中该列加1分(这样的声明没有选择器,所以它们的专用性总是1000。)否则为0。
  2. 百位:在整个选择器中每包含一个ID选择器就在该列中加1分。
  3. 十位:在整个选择器中每包含一个类选择器、属性选择器、或者伪类就在该列中加1分。
  4. 个位:在整个选择器中每包含一个元素选择器或伪元素就在该列中加1分。

注意: 通用选择器 (*), 复合选择器 (+, >, ~, ' ') 和否定伪类 (:not) 在专用性中无影响。

下表显示了几个示例。试着通过这些,并确保你理解他们为什么具有我们给予他们的专用性。

选择器 千位 百位 十位 个位 合计值
h1 0 0 0 1 0001
#important 0 1 0 0 0100
h1 + p::first-letter 0 0 0 3 0003
li > a[href*="zh-CN"] > .inline-warning 0 0 2 2 0022
#important div > div > a:hover, 在一个元素的 <style>属性里 1 1 1 3 1113

在我们继续之前,让我们看看一个行动中的例子。

这是我们将要使用的HTML:

  1. <div id="outer" class="container">
  2. <div id="inner" class="container">
  3. <ul>
  4. <li class="nav"><a href="#">One</a></li>
  5. <li class="nav"><a href="#">Two</a></li>
  6. </ul>
  7. </div>
  8. </div>

下面是CSS的示例:

  1. /* specificity: 0101 */
  2. #outer a {
  3. background-color: red;
  4. }
  5. /* specificity: 0201 */
  6. #outer #inner a {
  7. background-color: blue;
  8. }
  9. /* specificity: 0104 */
  10. #outer div ul li a {
  11. color: yellow;
  12. }
  13. /* specificity: 0113 */
  14. #outer div ul .nav a {
  15. color: white;
  16. }
  17. /* specificity: 0024 */
  18. div div li:nth-child(2) a:hover {
  19. border: 10px solid black;
  20. }
  21. /* specificity: 0023 */
  22. div li:nth-child(2) a:hover {
  23. border: 10px dashed black;
  24. }
  25. /* specificity: 0033 */
  26. div div .nav:nth-child(2) a:hover {
  27. border: 10px double black;
  28. }
  29. a {
  30. display: inline-block;
  31. line-height: 40px;
  32. font-size: 20px;
  33. text-decoration: none;
  34. text-align: center;
  35. width: 200px;
  36. margin-bottom: 10px;
  37. }
  38. ul {
  39. padding: 0;
  40. }
  41. li {
  42. list-style-type: none;
  43. }

我们从这个代码中得到的结果如下:

这里发生了什么?首先,我们只对本例的前七个规则感兴趣,正如您将注意到的,我们已经在每个注释中包含了它们的专用性值。

  • 前两个选择器正在竞争链接的背景颜色的样式——第二个赢得并使背景色为蓝色,因为它有一个额外的ID选择器在链中:其专用性值为201比101。
  • 第三个和第四个选择器在链接文本颜色的样式上进行竞争——第二个选择器获胜,使文本变白,因为缺少一个元素选择器,缺少的选择器被换成类选择器,它的值是十,而不是个位。所以专用性值为113和104。
  • 选择器5 - 7在徘徊在链接附近时的样式进行竞争。选择器六明显地输给了了五,其专用性值为23和24——它在链中少了一个元素选择器。然而选择器七同时击败了五和六——它有与五相同数量的子选择器在链中,但一个元素已被换为了一个类选择器。所以获胜的专用性值是33比23和24。

源代码次序

如上所述,如果多个相互竞争的选择器具有相同的重要性和专用性,那么第三个因素将帮助决定哪一个规则获胜——后面的规则将战胜先前的规则。例如:

  1. p {
  2. color: blue;
  3. }
  4. /* This rule will win over the first one */
  5. p {
  6. color: red;
  7. }

而在这个例子中的第一个规则将获胜,因为专用性高于源代码顺序:

  1. /* This rule will win */
  2. .footnote {
  3. color: blue;
  4. }
  5. p {
  6. color: red;
  7. }

关于规则混合的一点注记

在考虑所有这些层叠理论和什么样式优先于其他样式被应用时,你应该记住的一件事是,所有这些都发生在属性级别上——属性覆盖其他属性,但你不会让整个规则凌驾于其他规则之上。

当多个CSS规则匹配相同的元素时,它们都被应用到该元素中。只有在这之后,任何相互冲突的属性才会被评估,以确定哪种风格会战胜其他类型。

简记:只有相同的属性应用发生冲突后才会产生覆盖

让我们看一个例子。首先,一些HTML:

  1. <p>I'm <strong>important</strong></p>

现在一些CSS风格与它:

  1. /* specificity: 0002 */
  2. p strong {
  3. background-color: khaki;
  4. color: green;
  5. }
  6. /* specificity: 0001 */
  7. strong {
  8. text-decoration: underline;
  9. color: red;
  10. }

Result:

在这个例子中,因为专用性的关系,第一条规则中的color属性覆盖掉了第二条中的颜色值。但是,对于第一条中的 background-color和第二条中的text-decoration 的属性都在strong元素之中得到了体现。你也注意到了这个元素之中的字体是加粗的:这是浏览器默认的样式规则。

继承

CSS继承是我们需要研究的最后一部分,以获取所有信息并了解什么样式应用于元素。

其思想是,应用于某个元素的一些属性值将由该元素的子元素继承,而有些则不会。

  • 例如,对 font-familycolor进行继承是有意义的,因为这使得您可以很容易地设置一个站点范围的基本字体,方法是应用一个字体到 <html> 元素;然后,您可以在需要的地方覆盖单个元素的字体。如果要在每个元素上分别设置基本字体,那就太麻烦了。

  • 再如,让 margin paddingborderbackground-image 不被继承是有意义的。想象一下,如果您将这些属性设置在一个容器元素上,并将它们继承到每个子元素,然后不得不将它们全部放在每个单独的元素上,那么将会出现的样式/布局混乱。

哪些属性默认被继承哪些不被继承大部分符合常识。如果你想确定,你可以参考CSS参考资料—— 每个单独的属性页都会从一个汇总表开始,其中包含有关该元素的各种详细信息,包括是否被继承。

注:

font-family允许您通过给定一个有先后顺序的,由字体名或者字体族名组成的列表来为选定的元素设置字体。 属性的值用逗号隔开。浏览器会选择列表中第一个该计算机上有安装的字体,或者是通过 ‘ @font-face 指定的可以直接下载的字体。

padding属性设置一个元素的内边距,padding 区域指一个元素的内容和其边界之间的空间,该属性不能为负值。

background-image 属性用于为一个元素设置一个或者多个背景图像。图像在绘制时,以z方向堆叠的方式进行。先指定的图像会在之后指定的图像上面绘制。因此指定的第一个图像最接近用户。

控制继承

CSS为处理继承提供了四种特殊的通用属性值:

  • inherit: 该值将应用到选定元素的属性值设置为与其父元素一样。
  • initial :该值将应用到选定元素的属性值设置为与浏览器默认样式表中该元素设置的值一样。如果浏览器默认样式表中没有设置值,并且该属性是自然继承的,那么该属性值就被设置为 inherit
  • unset:该值将属性重置为其自然值,即如果属性是自然继承的,那么它就表现得像 inherit,否则就是表现得像 initial
  • revert:如果当前的节点没有应用任何样式,则将该属性恢复到它所拥有的值。换句话说,属性值被设置成自定义样式所定义的属性(如果被设置), 否则属性值被设置成用户代理的默认样式。

注意: initialunset 不被IE支持。

initial 是将属性的初始值( initial value)赋给元素 . initial 适用于所有的css 属性(属性的initial值可在属性表中查到),包括css 简写属性(全局属性)all.

inherit 值是最有趣的——它允许我们显式地让一个元素从其父类继承一个属性值。

让我们看一个例子。首先有以下一段HTML:

  1. <ul>
  2. <li>Default <a href="#">link</a> color</li>
  3. <li class="inherit">Inherit the <a href="#">link</a> color</li>
  4. <li class="initial">Reset the <a href="#">link</a> color</li>
  5. <li class="unset">Unset the <a href="#">link</a> color</li>
  6. </ul>

现在用CSS给它添加样式:

  1. body {
  2. color: green;
  3. }
  4. .inherit a {
  5. color: inherit;
  6. }
  7. .initial a {
  8. color: initial
  9. }
  10. .unset a {
  11. color: unset;
  12. }

Result:

让我们解释这里发生了什么:

  • 我们首先设置<body>color为绿色。
  • 由于color属性是自然继承的,所有的body子元素都会有相同的绿色。需要注意的是默认情况下浏览器设置链接的颜色为蓝色,而不是自然继承color属性,因此在我们列表中的第一个链接是蓝色的。
  • 第二个规则设置一个类 inherit 的元素内的链接,并从父类继承它的颜色。在这种情况下, 意思是说链接继承了父元素<li> 的颜色,默认情况下<li>的颜色来自于它的父元素 <ul> , 最后<ul>继承自 <body>元素,而<body>color 根据第一条规则设置成了绿色。
  • 第三个规则选择了在元素上使用类 initial 的任意链接然后设置他们的颜色为 initial 。通常, initial 的值被浏览器设置成了黑色,因此该链接被设置成了黑色。
  • 最后一个规则选择了在元素上使用类 unset 的所有链接然后设置它们的颜色为 unset ——即我们不设置值。因为color属性是一个自然继承的属性,它实际上就像把值设置成 inherit 一样。结果是,该链接被设置成了与body一样的颜色——绿色。

重新设置所有的属性值

CSS速写属性 all 能够被应用到每一个继承属性,一次性应用所有的继承属性。这里的值可以是继承属性里的任何一个 (inherit, initial, unset, or revert)。对于撤销对样式的修改,这是非常方便的一种方式。然后你就可以在开始新的修改之前,返回到一个已知的开始点。

全文摘要自MDN网络开发者网站

end

2018-5-31 周四

CSS学习摘要-层叠和继承的更多相关文章

  1. CSS学习摘要-定位实例

    CSS学习摘要-定位实例 注:全文摘自MDN-CSS定位实例 列表消息盒子 我们研究的第一个例子是一个经典的选项卡消息框,你想用一块小区域包括大量信息时,一个非常常用的特征.这包括含有大信息量的应用, ...

  2. CSS学习摘要-定位

    CSS学习摘要-定位 注:全文摘自MDN-CSS定位 定位允许您从正常的文档流布局中取出元素,并使它们具有不同的行为,例如放在另一个元素的上面,或者始终保持在浏览器视窗内的同一位置. 本文解释的是定位 ...

  3. CSS学习摘要-引入样式

    CSS学习摘要-引入样式 注:主要是摘录自MDN 网络开发者这个网站的. CSS 实际上如何工作? 当浏览器显示文档时,它必须将文档的内容与其样式信息结合.它分两个阶段处理文档: 浏览器将 HTML和 ...

  4. CSS学习摘要-语法和选择器

    主要摘自网络开发者. 从最基本的层次来看,CSS是由两块内容组合而成的: 属性(Property):一些人类可理解的标识符,这些标识符指出你想修改哪一些样式,例如:字体,宽度,背景颜色等. 属性值(V ...

  5. CSS学习(7)继承、属性值的计算过程

    子元素会继承父元素的某些css属性 通常跟字体相关的属性都能被继承,具体的可以在mdn里查询是否是可继承属性 属性值的计算过程(渲染过程) 按照页面文档的树形目录结构进行依次渲染 前提条件:渲染的元素 ...

  6. CSS学习摘要-布局

    注:全文摘自MDN-介绍CSS布局 CSS页面布局技术允许我们拾取网页中的元素,并且控制它们相对正常布局流.周边元素.父容器或者主视口/窗口的位置.在这个模块中将涉及更多关于页面布局技术的细节: 浮动 ...

  7. CSS学习摘要-浮动与清除浮动

    以下从浮动到BFC的段落 摘自MDN 网络开发者 float 浮动 float CSS属性指定一个元素应沿其容器的左侧或右侧放置,允许文本和内联元素环绕它.该元素从网页的正常流动中移除,尽管仍然保持部 ...

  8. CSS学习摘要-盒子模型

    注:全文摘要自网络开发者网站,当然间隔也会整理一些思路和格式排版添加进去. CSS框模型(译者注:也被称为"盒模型")是网页布局的基础 --每个元素被表示为一个矩形的方框,框的内容 ...

  9. CSS学习摘要-数值和单位及颜色

    在CSS中,值的类型有很多种,一些很常见,一些你却几乎没怎么遇到过.我们不会在这篇文档中面面俱到地描述他们,而只是这些对于掌握CSS可能最有用处的这些.本文将会涉及如下CSS的值: 数值: 长度值,用 ...

随机推荐

  1. sublime text3怎么让左侧显示目录树

    在前端开发中(包括Node.js开发),经常会使用sublime text,但之前一直不知道别人是怎么让左侧显示目录树,故特意在此记录一下. View ->Side Bar ->Show ...

  2. TCP三次握手/四次挥手

    TCP 三次握手 TCP 连接是通过三次握手进行初始化的.三次握手的目的是同步连接双方的序列号和确认号并交换 TCP 窗口大小信息.以下步骤概述了通常情况下客户端计算机联系服务器计算机的过程: 1.  ...

  3. 发起qq临时会话

    http://wpa.qq.com/msgrd?v=3&uin=947739614&site=qq&menu=yes

  4. 【转】手机web前端调试页面的几种方式

    前言 PC端web页面调试比较容易,这里主要说几种移动端调试的方法,从简单到复杂.从模拟调试到远程调试,大概分为几部分: 1.Chrome DevTools(谷歌浏览器)的模拟手机调试 2.weinr ...

  5. 使用IDEA工具配置和运行vue项目(详细其中的坑)

    刚来公司实习发现公司的前端使用的是vue,之前根本就没有听说过.然后一上来就需要看代码,but but 就是没有文档什么的东西, 就需要自己去研读,我就想去运行其中的前端和后端联调起来方便理解,结果在 ...

  6. Storm框架:如何消费RabbitMq消息(代码案例)

    1.定义拓扑topology public class MessageTopology { public static void main(String[] args) throws Exceptio ...

  7. tcpcopy + tcpdump 离线回放

    简单来说,就是用tcpdump记录线上请求,用tcpcopy来重放,如下图所示:   有关 tcpdump 的命令详解请参考: http://www.cnblogs.com/ggjucheng/arc ...

  8. 在IIS7中应用Application Request Routing配置反向代理

    配置反向代理软件.zip 开启Proxy项: 该设置表面只有HTTP_HOST为phpweb.leven.com.cn的URL才能通过该规则,如果您绑定了多个域名,可以根据多次增加或者通过正则表达式的 ...

  9. db2存储过程迁移

    一.导出存储过程 EXPORT TO D:/PROCUDURE/procudure.del OF del MODIFIED BY LOBSINFILE SELECT 'SET CURRENT SCHE ...

  10. python中垃圾回收机制

    Python垃圾回收机制详解   一.垃圾回收机制 Python中的垃圾回收是以引用计数为主,分代收集为辅.引用计数的缺陷是循环引用的问题.在Python中,如果一个对象的引用数为0,Python虚拟 ...