CSS学习- 层叠、优先级、继承

710 阅读8分钟
  • 层叠
  • 优先级
  • 继承

冲突规则

CSS代表层叠样式表

常见问题:

  • 你创建的效果没有生效,通常的原因是你创建了两个应用于同一个元素的规则。cascade,和它密切联系的概念是specificity, 决定在发生冲突的时候应该使用哪种规则。
  • 这里也有继承的概念

层叠

Stylesheets cascade(样式表层叠)-- 简单的说, css规则的顺序很重要: 当应用两条同级别的规则到一个元素时候,写在后面的就是实际使用的规则。

h1 { 
    color: red; 
}
h1 { 
    color: blue; 
}
<h1>This is my heading.</h1>

优先级

浏览器是根据优先级来决定当多个规则有不同选择器对应相同的元素的时候需要使用哪个规则。它基本上是一个衡量选择器具体选择哪些区域的尺度:

  • 一个元素选择器不是很具体 — 会选择页面上该类型的所有元素 — 所以它的优先级就会低一些。
  • 一个类选择器稍微具体点 — 它会选择该页面中有特定 class 属性值的元素 — 所以它的优先级就要高一点。
/* 优先使用的是.main-heading */
.main-heading { 
  color: red;
}

h1 {
  color: blue
}
<h1 class="main-heading">This is my heading.</h1>

继承

继承也需要在上下文中去理解 —— 一些设置在父元素上的css属性是可以被子元素继承的,有些则不能。

举一个例子,如果你设置一个元素的colorfont-family,每个在里面的元素也都会有相同的属性,除非你直接在元素上设置属性。

body {
    color: blue;
}

span {
    color: black;
}
<p>As the body has been set to have a color of blue this is inherited through the descendants.</p>
<p>We can change the color by targetting the element with a selector, such as this <span>span</span>.</p>

一些属性是不能继承的 — 举个例子如果你在一个元素上设置 width 50% ,所有的后代不会是父元素的宽度的50% 。如果这个也可以继承的话,CSS就会很难使用了!

理解这些概念是如何协同工作的

这三个概念一起来控制css规则应用于哪个元素;在下面的内容中,我们将看到它们是如何协同工作的。有时候会感觉有些复杂,但是当你对css有更多经验的时候,你就可以记住它们,即便忘记了细节,可以在网上查到,有经验的开发人员也不会记得所有细节。

理解继承

我们从继承开始。下面的例子中我们有一个ul,里面有两个无序列表, 我们已经给<ul>设置了border,paddingfont-color.

color 应用在直接子元素,也影响其他后代 — 直接子元素<li>,和第一个嵌套列表中的子项。然后添加了一个 special 类到第二个嵌套列表,其中使用了不同的颜色。然后通过它的子元素继承。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    .main {
        color: rebeccapurple;
    }
    .special {
        color: black;
        font-weight: bold;
    }
  </style>
</head>
<body>
<ul class="main">
  <li>Item One</li>
  <li>Item Two
    <ul>
      <li>2.1</li>
      <li>2.2</li>
    </ul>
  </li>
  <li>Item Three
    <ul class="special">
      <li>3.1
        <ul>
          <li>3.1.1</li>
          <li>3.1.2</li>
        </ul>
      </li>
      <li>3.2</li>
    </ul>
  </li>
</ul>
</body>
</html>

像 widths (上面提到的), margins, padding, 和 borders 不会被继承。如果borders可以被继承,每个列表和列表项都会获得一个边框 — 可能就不是我们想要的结果!

哪些属性属于默认继承很大程度上是由常识决定的。

控制继承

CSS 为控制继承提供了四个特殊的通用属性值。每个css属性都接收这些值。

inherit

设置该属性会使子元素属性和父元素相同。实际上,就是 "开启继承".

initial

设置属性值和浏览器默认样式相同。如果浏览器默认样式中未设置且该属性是自然继承的,那么会设置为 inherit

unset

将属性重置为自然值,也就是如果属性是自然继承那么就是 inherit,否则和 initial一样

注: 还有一个新的属性, revert, 只有很少的浏览器支持。

body {
    color: green;
}
          
.my-class-1 a {
    color: inherit;
}
          
.my-class-2 a {
    color: initial;
}
          
.my-class-3 a {
    color: unset;
}
<ul>
    <li>Default <a href="#">link</a> color</li>
    <li class="my-class-1">Inherit the <a href="#">link</a> color</li>
    <li class="my-class-2">Reset the <a href="#">link</a> color</li>
    <li class="my-class-3">Unset the <a href="#">link</a> color</li>
</ul>

重设所有属性值

CSS 的 shorthand 属性 all 可以用于同时将这些继承值中的一个应用于(几乎)所有属性。它的值可以是其中任意一个(inherit, initial, unset, or revert)。这是一种撤销对样式所做更改的简便方法,以便回到之前已知的起点。

下面的例子中有两个blockquote 。第一个用元素本身的样式 ,第二个设置 allunset

理解层叠

我们现在明白了为什么嵌套在html结构中的段落和应用于正文中的css颜色相同,从入门课程中,我们了解了如何将文档中的任何修改应用于某个对象的css,无论是把css指定某个元素还是创建一个类。现在,我们将要了解层叠如何定义在不止一个元素的时候怎么应用css规则。

有三个因素需要考虑,根据重要性排序如下,前面的更重要:

  1. 重要程度
  2. 优先级
  3. 资源顺序

我们从下往上,看看浏览器是如何决定该应用哪个css规则的。

资源顺序

我们已经看到了顺序对于层叠的重要性。如果你有超过一条规则,而且都是相同的权重,那么最后面的规则会应用。可以理解为后面的规则覆盖前面的规则,直到最后一个开始设置样式。

优先级

在你了解了顺序的重要性后,会发现在一些情况下,有些规则在最后出现,但是却应用了前面的规则。这是因为前面的有更高的优先级 — 它范围更小,因此浏览器就把它选择为元素的样式。

就像前面看到的,类选择器的权重大于元素选择器,因此类上定义的属性将覆盖应用于元素上的属性。

这里需要注意虽然我们考虑的是选择器,以及应用在选中对象上的规则,但不会覆盖所有规则,只有相同的属性。

这样可以避免重复的 CSS。一种常见的做法是给基本元素定义通用样式,然后给不同的元素创建对应的类。举个例子,在下面的样式中我给2级标题定义了通用样式,然后创建了一些类只修改部分属性的值。最初定义的值应用于所有标题,然后更具体的值通过对应类来实现。

h2 {
    font-size: 2em;
    color: #000;
    font-family: Georgia, 'Times New Roman', Times, serif;
}
        
.small {
    font-size: 1em;
}
        
.bright {
    color: rebeccapurple;
}  
<h2>Heading with no class</h2>
<h2 class="small">Heading with class of small</h2>
<h2 class="bright">Heading with class of bright</h2>

现在让我们来看看浏览器如何计算优先级。我们已经知道一个元素选择器比类选择器的优先级更低会被其覆盖。本质上,不同类型的选择器有不同的分数值,把这些分数相加就得到特定选择器的权重,然后就可以进行匹配。

一个选择器的优先级可以说是由四个部分相加 (分量),可以认为是个十百千 — 四位数的四个位数:

  1. 千位: 如果声明在 style 的属性(内联样式)则该位得一分。这样的声明没有选择器,所以它得分总是1000。
  2. 百位: 选择器中包含ID选择器则该位得一分。
  3. 十位: 选择器中包含类选择器、属性选择器或者伪类则该位得一分。
  4. 个位:选择器中包含元素、伪元素选择器则该位得一分。

:通用选择器 (*),组合符 (+, >, ~, ' '),和否定伪类 (:not) 不会影响优先级。

选择器千位百位十位个位优先级
h100010001
h1 + p::first-letter00030003
li > a[href*="en-US"] > .inline-warning00220022
#identifier01000100
内联样式10001000
/* specificity: 0101 */
#outer a {
    background-color: red;
}
        
/* specificity: 0201 */
#outer #inner a {
    background-color: blue;
}

/* specificity: 0104 */
#outer div ul li a {
    color: yellow;
}

/* specificity: 0113 */
#outer div ul .nav a {
    color: white;
}

/* specificity: 0024 */
div div li:nth-child(2) a:hover {
    border: 10px solid black;
}

/* specificity: 0023 */
div li:nth-child(2) a:hover {
    border: 10px dashed black;
}

/* specificity: 0033 */
div div .nav:nth-child(2) a:hover {
    border: 10px double black;
}

a {
    display: inline-block;
    line-height: 40px;
    font-size: 20px;
    text-decoration: none;
    text-align: center;
    width: 200px;
    margin-bottom: 10px;
}

ul {
    padding: 0;
}

li {
    list-style-type: none;
} 
<div id="outer" class="container">
    <div id="inner" class="container">
        <ul>
            <li class="nav"><a href="#">One</a></li>
            <li class="nav"><a href="#">Two</a></li>
        </ul>
    </div>
</div>

!important

有一个特殊的 CSS 可以用来覆盖所有上面所有优先级计算,不过需要很小心的使用 — !important。用于修改特定属性的值, 能够覆盖普通规则的层叠。

: 覆盖 !important 唯一的办法就是另一个 !important 具有 相同优先级 而且顺序靠后,或者更高优先级。

了解 !important 是为了在阅读别人代码的时候知道有什么作用。 但是,强烈建议除了非常情况不要使用它。 !important 改变了层叠的常规工作方式,它会使调试 CSS 问题非常困难,特别是在大型样式表中。

CSS的位置影响

最后,也很有用,CSS声明的重要性取决于样式表中指定的——它让用户可以设置自定义样式表来覆盖开发人员定义的样式。例如用户可能视力受损,并想在所有网页上设置两倍的正常字体大小,以便更容易进行阅读。