CSS 作用域自定义属性在用于计算外部作用域中的变量时被忽略

2024-04-24

我正在尝试通过缩放尺寸var自定义属性的方式是类无需耦合即可组合。期望的效果是 3 个列表将具有 3 个不同的比例,但作为在 CodePen 上演示 https://codepen.io/ryanve/pen/WgrjxL所有 3 个列表的比例相同。我正在寻找范围界定和 CSS 自定义属性技术的解释,该技术可以通过可组合的松散耦合代码来实现此目的。

:root {
  --size-1: calc(1 * var(--scale, 1) * 1rem);
  --size-2: calc(2 * var(--scale, 1) * 1rem);
  --size-3: calc(3 * var(--scale, 1) * 1rem);
}

.size-1 { font-size: var(--size-1) }
.size-2 { font-size: var(--size-2) }
.size-3 { font-size: var(--size-3) }

.scale-1x { --scale: 1 }
.scale-2x { --scale: 2 }
.scale-3x { --scale: 3 }

html {
  font: 1em sans-serif;
  background: papayawhip;
}

ol {
  float: left;
  list-style: none;
  margin: 1rem;
}
<ol class="scale-1x">
  <li class="size-1">size 1</li>
  <li class="size-2">size 2</li>
  <li class="size-3">size 3</li>
</ol>
<ol class="scale-2x">
  <li class="size-1">size 1</li>
  <li class="size-2">size 2</li>
  <li class="size-3">size 3</li>
</ol>
<ol class="scale-3x">
  <li class="size-1">size 1</li>
  <li class="size-2">size 2</li>
  <li class="size-3">size 3</li>
</ol>

就您而言,您已经评估了--scale根级别的自定义属性来定义--size-*属性,然后你定义了--scale again在子元素内。这不会再次触发评估,因为它已经在更高级别.

下面用一个简单的例子来说明这个问题:

.box {
  --color: var(--c, blue);
}

span {
  color: var(--color);
}
<div>
  <div class="box"><!-- --c is evaluated at this level -->
    <span style="--c:red">I will not be red because the property is already evaluated and --color is set to blue using the default value</span>
  </div>
</div>

<div style="--c:red">
  <div class="box"><!-- --c is evaluated at this level -->
    <span>I will be red because at the time of the evaluation --c is red (inherited from the upper div)</span>
  </div>
</div>

要解决您的问题,您需要将声明从:root--scale定义:

.scale {
  --size-1: calc(1 * var(--scale, 1) * 1rem);
  --size-2: calc(2 * var(--scale, 1) * 1rem);
  --size-3: calc(3 * var(--scale, 1) * 1rem);
}

.size-1 { font-size: var(--size-1) }
.size-2 { font-size: var(--size-2) }
.size-3 { font-size: var(--size-3) }

.scale-1x { --scale: 1 }
.scale-2x { --scale: 2 }
.scale-3x { --scale: 3 }


html {
  font: 1em sans-serif;
  background: papayawhip;
}

ol {
  float: left;
  list-style: none;
  margin: 1rem;
}
<ol class="scale-1x scale">
  <li class="size-1">size 1</li>
  <li class="size-2">size 2</li>
  <li class="size-3">size 3</li>
</ol>
<ol class="scale-2x scale">
  <li class="size-1">size 1</li>
  <li class="size-2">size 2</li>
  <li class="size-3">size 3</li>
</ol>
<ol class="scale-3x scale">
  <li class="size-1">size 1</li>
  <li class="size-2">size 2</li>
  <li class="size-3">size 3</li>
</ol>

在这种情况下,--scale被定义在与其评估相同的级别,因此--size-*将为每种情况正确定义。


From 规格 https://www.w3.org/TR/css-variables-1/#using-variables:

To 替换 var()在财产价值中:

  1. 如果自定义属性由 var() 的第一个参数命名 函数受到动画污染,并且 var() 函数正在使用 动画属性或其常用方法之一,请对待自定义 属性具有该算法其余部分的初始值。
  2. 如果由第一个参数命名的自定义属性的值 var() 函数不是初始值,替换 var() 函数通过相应的自定义属性的值。否则,
  3. 如果 var() 函数有一个后备值作为其第二个参数, 将 var() 函数替换为后备值。如果有的话 后备中的 var() 引用,也替换它们。
  4. 否则,包含 var() 函数的属性在以下位置无效 计算值时间

在你的第一种情况下,你陷入了3因为没有指定值--scale在根级别。在最后一种情况下,我们陷入了2因为我们定义了--scale在同一水平上,我们有它的价值。


在所有情况下,我们应该避免任何评估:root级别,因为它根本没用。根级别是 DOM 中的最高级别,因此所有元素都将继承相同的值,并且除非我们再次评估变量,否则 DOM 内不可能有不同的值。

您的代码相当于以下代码:

:root {
  --size-1: calc(1 * 1 * 1rem);
  --size-2: calc(2 * 1 * 1rem);
  --size-3: calc(3 * 1 * 1rem);
}

我们再举一个例子:

:root {
  --r:0;
  --g:0;
  --b:255;
  --color:rgb(var(--r),var(--g),var(--b))
}
div {
  color:var(--color);
}
p {
  --g:100;
  color:var(--color);
}
<div>
  some text
</div>
<p>
  some text
</p>

直觉上,我们可能会认为我们可以改变--color通过更改定义在的 3 个变量之一:rootlevel 但我们不能这样做,上面的代码与此相同:

:root {
  --color:rgb(0,0,255)
}
div {
  color:var(--color);
}
p {
  --g:100;
  color:var(--color);
}
<div>
  some text
</div>
<p>
  some text
</p>

3 个变量(--r, --g, --b)在里面评估:root所以我们已经用它们的值替换了它们。

在这种情况下我们有3种可能:

  • 更改里面的变量:root使用 JS 或其他 CSS 规则。这不允许我们有不同的颜色:
:root {
  --r:0;
  --g:0;
  --b:255;
  --color:rgb(var(--r),var(--g),var(--b))
}
div {
  color:var(--color);
}
p {
  --g:200; /*this will not have any effect !*/
  color:var(--color);
}

:root {
  --g:200; /*this will work*/
}
<div>
  some text
</div>
<p>
  some text
</p>
  • 在所需元素内再次评估变量。在这种情况下,我们将失去任何形式的灵活性和内部的定义:root将变得无用(或者至少将成为默认值):
:root {
  --r:0;
  --g:0;
  --b:255;
  --color:rgb(var(--r),var(--g),var(--b))
}
div {
  color:var(--color);
}
p {
  --g:200;
  --color:rgb(var(--r),var(--g),var(--b));
  color:var(--color);
}
<div>
  some text
</div>
<p>
  some text
</p>
  • 改变:root带有通用选择器的选择器*。这将确保我们的函数在所有级别上都得到定义和评估。在某些复杂的情况下,这可能会产生一些不需要的结果
* {
  --r:0;
  --g:0;
  --b:255;
  --color:rgb(var(--r),var(--g),var(--b))
}
div {
  color:var(--color);
}
p {
  --g:200;
  color:var(--color);
}
<div>
  some text
</div>
<p>
  some text
</p>

考虑到这一点,我们应该始终将求值保持在 DOM 树中尽可能最低的点,尤其是变量改变后(或同一级别)

这是我们不应该做的

:root {
  --r: 0;
  --g: 0;
  --b: 0;
}
.color {
  --color: rgb(var(--r), var(--g), var(--b))
}
.green {
  --g: 255;
}
.red {
  --r: 255;
}
p {
  color: var(--color);
}

h1 {
  border-bottom: 1px solid var(--color);
}
<div class="color">
  <h1 class="red">Red </h1>
  <p class="red">I want to be red :(</p>
</div>
<div class="color">
  <h1 class="green">Green </h1>
  <p class="green">I want to be green :(</p>
</div>

这是我们应该做的

:root {
  --r:0;
  --g:0;
  --b:0;
}
.color {
  --color:rgb(var(--r),var(--g),var(--b));
}

.green {
  --g:255;
}

.red {
  --r:255;
}

p {
  color:var(--color);
}
h1 {
  border-bottom: 1px solid var(--color);
}
<div class="red">
  <h1 class="color">Red title</h1>
  <p class="color">Yes I am red :D</p>
</div>
<div class="green">
  <h1 class="color">Green title</h1>
  <p class="color">Yes I am green :D</p>
</div>

我们也可以这样做:

:root {
  --r:0;
  --g:0;
  --b:0;
}
.color {
  --color:rgb(var(--r),var(--g),var(--b));
}

.green {
  --g:255;
}

.red {
  --r:255;
}

p {
  color:var(--color);
}
h1 {
  border-bottom: 1px solid var(--color);
}
<div class="red color">
  <h1 >Red title</h1>
  <p >Yes I am red :D</p>
</div>
<div class="green color">
  <h1>Green title</h1>
  <p >Yes I am green :D</p>
</div>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CSS 作用域自定义属性在用于计算外部作用域中的变量时被忽略 的相关文章

随机推荐