原文链接:

https://elad.medium.com/understanding-the-initial-inherit-and-unset-css-keywords-2d70b7121695

本文已归纳在 Github

更新


2021-2-20

  • Initial release

概述


CSS 中有各种各样的关键字。本文我将着重介绍以下几个关键字:initialinherit 以及较新的 unset

我确信绝大多数开发者都见过这几个关键字,但是对于它们的原理确知之甚少。

1.png

在此之前的一段时间,我只知道这些关键字是用来重置 CSS 样式的,但是如果它们都起到了重置的效果,又为什么会有这么多种呢?它们之间的区别又是什么?于是,我决定深入探索它们的原理

浏览器的基础样式


在开始讲解这些 CSS 关键字之前,我们首先要了解浏览器的基础样式是从哪儿来的。

CSS 属性的初始值

每个 CSS 属性都有一个初始值,这个值和 HTML 元素没有任何关系。

如下图所示的是从 MDN 上摘取的关于 initial 的例子:

2.jpeg

浏览器默认(User-Agent)样式表

在所有的 CSS 属性都设置完初始样式之后,紧接着浏览器会加载自身的样式表。该样式表与 CSS 属性的初始值没有任何关系。

user-agent 样式示例如下:

3.png

HTML 元素是没有初始的样式值的!上图中 <h1> 标签的基础样式是从 user agent stylesheet 中获取的,而不是 CSS 属性的初始值 initial

下面,让我们开始讲解这些 CSS 关键字吧!

Inherit 关键字


inherit 关键字告诉浏览器去寻找离当前 HTML 元素最近的父级元素,然后继承该父级元素对应的 CSS 属性值。如果父级元素的 CSS 属性值也是 inherit 的话,会继续一层层的向上查找,直到最后一个 DOM 元素,如果还是没有找到对应的 CSS 属性值的话,就会使用浏览器默认样式表(user-agent-stylesheet)中的属性值,如果没有 user-agent 样式表,最后会使用初始值 initial

See the Pen inherit css style by Elad Shechter (@elad2412) on CodePen.

Initial 关键字


在学习 initial 关键字之前,我们首先要搞清楚:每个 CSS 属性都有一个初始值,该初始值和 user-agent 样式没有任何关系。 User-agent 是浏览器针对 HTML 元素所定义的基本样式表。我们倾向于把 user-agent 样式表理解为是 HTML 自带的,但实际上不是的。

initial 关键字告诉浏览器去使用 CSS 属性的初始值,举个例子:

  • color 属性的 initial 值总是 black

上述行为可能会产生一个困惑:CSS 属性的初始值并不一定和浏览器默认样式表中相应的属性值相同。比如:所有 HTML 元素的 display 属性的 initial 值都为 inline,因此如果把 <div> 元素的 display 属性值设为 initial,那么实际上此时的 initial 就是 inline 而不是 user-agent 中的属性值 block

举个例子:

1
2
3
4
div.box{
background-color: red;
display: initial; /* initial 的值为 `inline` 而不是 `block` */
}

CodePen 在线示例:div 元素的 display 属性的 Initial 值

4.png

Unset 关键字


unset 关键字比较特别,它会根据不同类型的 CSS 属性来进行重置。CSS 属性有两种类型:

  • 可继承的属性 —— 当前 HTML 元素的 CSS 属性会影响它的后代元素。所有文本类型的 CSS 属性都有这个继承行为。比如:如果你给某个 HTML 元素设置了 font-size 属性,那么该元素的所有后代元素都会继承这个 font-size,除非你给某个后代元素又重新设置了 font-size
    5.png
  • 不可继承的属性 —— 当前 HTML 元素的 CSS 属性只对自身有效。除了文本类型之外的其它 CSS 属性都是不可继承的。比如:给某个 HTML 元素设置一个 border CSS 属性,该元素的后代元素不会同步的获得这个属性。
    6.png

对于可继承的属性,unset 的效果和 inherit 一样。例如:对于文本类型的 CSS 属性 colorunset 会一层层的向上查找,直到最后一个 HTML 元素,如果没有 color 属性值,那么就会查找 user-agent 样式表,如果还是没有,最后就直接使用 initial 初始值了。

对于不可继承的属性,unset 的效果和 initial 一样,直接使用该 CSS 属性的初始值。例如:border-color: unset 就等同于 border-color: initial

1
2
3
4
.some-class{
color: unset; /* = inherit */
display: unset; /* = initial = inline */
}

为什么要使用 Unset?

既然已经有了 initialinherit 关键字,为啥还要用 unset 呢?

如果只是重置单个 CSS 属性的值,那么就没必要使用 unset,使用 initialinherit 就可以了。

但是由于全新的 CSS 属性 all 的出现,让我们可以一次性重置所有属性的值,包括可继承属性不可继承属性

all 的值设为 unset,就可以实现:所有的可继承属性的值变为 inherit,所有的不可继承属性的值变为 initial

这是 unset 这个关键字存在的唯一原因!除此之外,你完全可以用 inheritinitial 关键字替代 unset

如果我们一个个的书写重置属性,代码会像下面这样:

1
2
3
4
5
6
7
/* Bad */
.common-content * {
font-size: inherit;
font-weight: inherit;
border-width: initial;
background-color: initial;
}

如果我们使用 all 属性搭配 unset 属性值,会影响当前所有的 CSS 属性,代码如下:

1
2
3
4
/* Good */
.common-content * {
all: unset;
}

我为此专门写了一个例子,详情可见:all: unset 在线示例

Revert 关键字


如果我们想把某个 CSS 属性的值重置为 user-agent 样式表中对应的样式值而不是该属性的初始值,我们应该怎么做呢?举个例子:怎么把 <div> 元素的值重置为 block(user-agent 样式),而不是 inline(初始值)?

7.png

为了解决这个问题,又出现了新的 CSS 关键字:revertrevertunset 非常像,唯一的区别在于 revert 会把 CSS 属性值重置为 user-agent 中对应的值,举个例子:

1
2
3
4
5
6
7
div {
display: revert; /* = block */
}
h1 {
font-weight: revert; /* = bold */
font-size: revert; /* = 2em */
}

也可以一次性重置当前 HTML 元素的所有 CSS 属性:

1
2
3
4
/* Good */
.common-content * {
all: revert;
}

revert 相较于 unset 更加实用,但是浏览器兼容性不太好,目前只能在 Firefox 和 Safari 上正常工作。

浏览器兼容性


  • inherit —— 包括 IE11 在内的所有浏览器都支持
  • initial & unset —— 除了 IE11 之外的所有浏览器都支持
  • revert —— 目前只支持 Firefox & Safari