Skip to content

层叠、优先级和继承

1. 层叠

CSS 本质上就是声明规则,浏览器根据这些规则去渲染页面。

当声明发生冲突时,层叠会依据三种规则去解决冲突:

  1. 样式表的来源:样式是从哪里来的。
  2. 选择器优先级:哪些选择器更重要。
  3. 源码顺序:样式在样式表里的声明顺序。

1.1 样式表的来源

  • 通过 CSS 自定义的样式属于作者样式表,此外还有用户代理样式表,即浏览器默认样式。
  • 用户代理样式表优先级低,作者样式表会覆盖它们。

说明

有些浏览器允许用户创建一个用户样式表,优先级介于作者样式表和用户代理样式表之间,用户样式表很少见。

  • 用户代理样式在不同的浏览器中稍有差异。
  • !important:在样式声明的后面,分号的前面加上 !important,该声明就会标记为重要的声明,该声明会当作更高优先级的来源。
  • 来源总体优先级:作者的 !important > 作者 > 用户代理。

1.2 理解优先级

如果无法用来源解决冲突声明,浏览器会尝试检查它们的优先级。

1.2.1 行内样式

  • 如果用 HTML 的 style 属性写的样式就是行内样式,只作用于当前元素。
  • 行内样式会覆盖任何来自样式表或者 <style> 标签的样式(除了重要声明之外)。
  • 行内样式没有选择器。
  • 在样式表中给样式添加 !important 就会覆盖行内声明,但如果行内样式也使用了 !important 标记,则无法被覆盖。实践中最好只在样式表中使用 !important

1.2.2 选择器优先级

  • 如果选择器的 ID 更多,则优先级更高。
  • 如果 ID 选择器数量一样,那么拥有更多类的选择器胜出。
  • 如果上述比较都一致,则拥有更多标签名的选择器胜出。
  • 伪类选择器如 :hover 和属性选择器如 [type="input"] 与一个类选择器优先级相同。通用选择器 * 和组合器 +>~ 对优先级没影响。

1.3 源码顺序

如果两个声明的来源和优先级相同,其中一个声明在样式表中出现较晚,或者位于页面较晚引入的样式表中,则该声明胜出。

1.3.1 链接样式和源码顺序

给链接加伪类样式要按一定的顺序书写,否则后面的样式可能覆盖前面的样式,导致样式不起作用:

css
a:link {
  color: blue;
  text-decoration: none;
}
a:visited {
  color: purple;
}
a:hover {
  text-decoration: underline;
}
a:active {
  color: red;
}

1.3.2 层叠值

  • 按来源、优先级、源码顺序来解析元素的样式,最终胜出的属性声明就是层叠值。
  • 元素的每个属性最多只有一个层叠值。

1.4 两条经验法则

  1. 选择器中尽量不使用 ID 选择器。
  2. 尽量不使用 !important 声明,因为它比 ID 选择器优先级更高,更难覆盖。

2. 继承

如果一个元素的某个属性没有层叠值,则可能会继承某个祖先元素的值。如通常会给 <body> 元素设置 font-family,所有后代元素都会加上这个字体。

默认情况下,只有特定的一些属性能够继承:

  • 跟文本相关的属性:colorfontfont-familyfont-sizefont-weightfont-styleline-heightletter-spacingtext-aligntext-indenttext-transformwhite-space 以及 word-spacing
  • 列表属性:list-stylelist-style-typelist-style-positionlist-style-image
  • 表格的边框属性:border-collapseborder-spacing

3. 特殊值

3.1 inherit 关键字

  • 使用 inherit 关键字可以用继承替代一个层叠值,该元素会继承其父元素的值。
  • 通常不会被继承的属性,可以通过 inherit 关键字强制继承。
css
.footer {
  color: #666;
  ...
}

.footer a {
  /* 页脚链接的颜色随页脚颜色而改变 */
  color: inherit; 
}

3.2 initial 关键字

  • 使用 initial 关键字可以撤销作用于某元素的样式。
  • 每个 CSS 属性都有默认值,将 initial 赋给某元素,会将其置为默认值。
css
.footer a {
  /* 链接为黑色,在大多数浏览器中,黑色是 color 属性的初始值 */
  color: initial;
}

4. 简写属性

简写属性是用于同时给多个属性赋值的属性。如:

  • font:指定了 font-stylefont-weightfont-sizefont-heightfont-family
  • background:指定了 background-colorbackground-imagebackground-sizebackground-repeatbackground-positionbackground-originbackground-clipbackground-attachment
  • border:指定了 border-widthborder-styleborder-color,这几个属性也都是简写属性。

4.1 简写属性会覆盖其它样式

  • 大部分简写属性可以省略一些值,不写的属性仍会隐式设置为初始值。这会默默覆盖在其它地方定义的样式。
  • font 属性尤其需要注意,要避免在 <body> 元素的通用样式之外使用 font
css
h1 {
  font-weight: bold;
}

.title {
  font: 32px Helvetica, Arial, snas-serif;
}

/* 后面 font 属性省略了 font-weight,会设置为默认 normal */

4.2 理解简写值的属性

很多简写属性的值遵循一定顺序,主要分为两种。

4.2.1 上、右、下、左

  • marginpadding 这样的属性,以及为元素四条边指定值的边框属性,值得顺序都是顺时针的,从上方开始。
  • 当只写了三个值时,左边和右边都会使用第二个值。
  • 只写了两个值时,第一个用与上下,第二个值用于左右。

4.2.2 水平、垂直

  • 有的属性只能设置两个方向的值,代表水平和垂直方向(笛卡尔网格),此时第一个值代表水平(左右),第二个值代表垂直(上下)。
  • 这些属性包括 background-positionbox-shadowtext-shadow 等。

总结:如果属性需要指定从一个点出发的两个方向的值,就想想水平和垂直,如果需要指定一个元素的四个方向的值,就想想顺时针。