首先我们来看一个简单的问题,下面的代码 .div2 的背景色应该是红色,浅蓝色还是浅绿色?
<style>
:root {
--color: red;
}
.div1 {
--color: lightblue;
--bg-color: var(--color);
}
.div2 {
--color: lightgreen;
background: var(--bg-color);
}
</style>
<div class="div1">
<div class="div2">test</div>
</div>
我们都知道 CSS 的第一个字母 C 代表 Cascading(中文是层叠),表示样式可以有多个来源,发生冲突时取优先级最高的样式作为最终样式。所以我们可以猜测 .div2 的背景色应该是浅绿色,因为 .div2 的 background 属性的值是 var(--bg-color),而 --bg-color 的值是 var(--color),而 --color 的值按优先级最高的应该是 lightgreen,所以 .div2 的背景色应该是浅绿色。
我们可以先看一下开发者工具给出的结果:

点击之后是跳到了 lightgreen ,奇怪的是前面的方框和鼠标悬浮展示的颜色是 lightblue。
看一下最终渲染出来的结果:
居然是浅蓝色,是浏览器 bug 导致优先级“错误”了么?
我们再来看一个CSS 规范中的例子:
<one>
<two>
<three />
</two>
</one>
<style>
one {
--foo: 10px;
}
two {
--bar: calc(var(--foo) + 10px);
}
three {
--foo: calc(var(--bar) + 10px);
}
</style>
three 的 --foo 应该是是多高?答案是 30px。
It is important to note that custom properties resolve any var() functions in their values at computed-value time, which occurs before the value is inherited. In general, cyclic dependencies occur only when multiple custom properties on the same element refer to each other; custom properties defined on elements higher in the element tree can never cause a cyclic reference with properties defined on elements lower in the element tree.
翻译:
需要注意的是,自定义属性会在计算值时(继承之前)在其值中解析 var() 函数。一般来说,只有当同一个元素上的多个自定义属性相互引用时,才会发生循环依赖;在元素树中较高位置的元素上定义的自定义属性,永远不会导致元素树中较低位置元素上定义的属性的循环引用。
现在我们可以得到一个简单的答案,这不是浏览器的 bug(虽然开发者工具有一些 bug),而是有意这样设计的,为了避免循环引用。
练习:
- wpt/css/css-variables/variable-declaration-51.html at master · web-platform-tests/wpt
- wpt/css/css-variables/variable-declaration-52.html at master · web-platform-tests/wpt
- wpt/css/css-variables/variable-declaration-58.html at master · web-platform-tests/wpt
- wpt/css/css-variables/variable-declaration-60.html at master · web-platform-tests/wpt
更多练习: