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

标签 css scope css-variables

我正在尝试通过 var 缩放尺寸自定义属性,类可以在没有耦合的情况下组合。预期的效果是这 3 个列表将处于 3 个不同的比例,但为 demonstrated on CodePen所有 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再次在子元素内。这不会再次触发评估,因为它已经在 中完成了。上层 .
下面是一个简单的例子来说明这个问题:

.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-*将针对每种情况正确定义。

来自 the specification :

To substitute a var() in a property’s value:

  1. If the custom property named by the first argument to the var() function is animation-tainted, and the var() function is being used in the animation property or one of its longhands, treat the custom property as having its initial value for the rest of this algorithm.
  2. If the value of the custom property named by the first argument to the var() function is anything but the initial value, replace the var() function by the value of the corresponding custom property. Otherwise,
  3. if the var() function has a fallback value as its second argument, replace the var() function by the fallback value. If there are any var() references in the fallback, substitute them as well.
  4. Otherwise, the property containing the var() function is invalid at computed-value time

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

在所有情况下,我们都应该避免在 :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通过更改 :root 中定义的 3 个变量之一级别,但我们不能这样做,上面的代码与此相同:

: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>

    关于用于计算外部作用域中的变量时忽略 CSS 作用域自定义属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52015737/

    相关文章:

    javascript - react css 优先级

    javascript - 水平放置的提交按钮和错误消息的正确对齐

    angularjs - AngularJS 中的范围未更新

    html - CSS 变量 : input:focus doesn't set variable

    webpack - 我可以使用带有 webpack 的 cssnext 来创建一个变量文件吗?

    jquery - 固定 Bootstrap 导航栏下的模糊效果

    javascript - ul list 不在按键时滚动,但它与鼠标滚轮一起滚动

    tsql - 如何访问通过调用 TSQL 中的存储过程生成的当前范围内的数据集?

    linux - 无法从嵌套子 shell 传递变量

    css - 如何调试 CSS calc() 值?