用于计算外部范围内的变量时,CSS 范围内的自定义属性被忽略
我正在尝试通过 var
自定义属性来缩放大小,以使类可以在不耦合的情况下组合.期望的效果是这 3 个列表将具有 3 个不同的比例,但正如 在 CodePen 上展示的 所有 3列表是相同的比例.我正在寻找有关范围和 CSS 自定义属性技术的解释,该技术可以通过可组合的松散耦合代码实现这一目标.
I'm attempting to scale size via a var
custom property in a way that the classes would compose without being coupled. The desired effect is that the 3 lists would be at 3 different scales but as demonstrated on CodePen all 3 lists are the same scale. I'm looking for an explanation of the scoping and a CSS custom property technique that could achieve this with composable loosely coupled code.
: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.这不会再次触发评估,因为它已经在上层中完成.
In your case you have evaluated the --scale
custom property at the root level to define the --size-*
properties and then you defined the --scale
again inside child elements. This will not trigger evaluation again because it was already done in an upper level.
这里有一个简单的例子来说明这个问题:
Here is a simple example to illustrate the issue:
.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
定义相同的级别:
To fix your issue, you need to move the declaration from :root
to the same level as the --scale
definition:
.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-*
将为每种情况正确定义.
In this case, --scale
is defined at the same level as its evaluation so --size-*
will be defined correctly for each case.
来自规范:
用 var() 替换属性值:
To substitute a var() in a property’s value:
- 如果自定义属性由 var() 的第一个参数命名函数被动画污染,并且 var() 函数被用于动画属性或其长手之一,对待自定义属性具有该算法其余部分的初始值.
- 如果由第一个参数命名的自定义属性的值var() 函数不是初始值,替换 var()通过相应自定义属性的值起作用.否则,
- 如果 var() 函数有一个备用值作为它的第二个参数,用回退值替换 var() 函数.如果有的话var() 后备中的引用,也可以替换它们.
- 否则,包含 var() 函数的属性在计算值时间
在您的第一种情况下,您将陷入 3,因为在根级别没有为 --scale
指定值.在最后一种情况下,我们陷入了 2,因为我们在同一级别定义了 --scale
并且我们有它的值.
In your first situation, you are falling into 3 because there is no value specified for --scale
at the root level. In the last case we are falling into 2 because we defined --scale
at the same level and we have its value.
在所有情况下,我们都应该避免在 :root
级别进行任何评估,因为它根本没有用.根级别是 DOM 中的最高级别,因此所有元素都将继承相同的值,并且除非我们再次评估变量,否则 DOM 内不可能有不同的值.
In all the cases, we should avoid any evaluation at :root
level because it's simply useless. The root level is the uppermost level in the DOM so all the elements will inherit the same value and it's impossible to have different values inside the DOM unless we evaluate the variable again.
你的代码相当于这个:
:root {
--size-1: calc(1 * 1 * 1rem);
--size-2: calc(2 * 1 * 1rem);
--size-3: calc(3 * 1 * 1rem);
}
我们再举一个例子:
Let's take another example:
: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>
直觉上,我们可能认为我们可以通过更改在 :root
级别定义的 3 个变量之一来更改 --color
,但我们不能这样做和上述代码和这个一样:
Intuitively, we may think that we can change the --color
by changing one of the 3 variables defined at :root
level but we cannot do this and the above code is the same as this one:
:root {
--color:rgb(0,0,255)
}
div {
color:var(--color);
}
p {
--g:100;
color:var(--color);
}
<div>
some text
</div>
<p>
some text
</p>
三个变量(--r
、--g
、--b
)在 :root
所以我们已经用它们的值替换了它们.
The 3 variables (--r
, --g
, --b
) are evaluated inside :root
so we have already substituted them with their values.
在这种情况下,我们有 3 种可能性:
In such a situation we have 3 possibilities:
- 使用 JS 或其他 CSS 规则更改
:root
内的变量.这不会让我们有不同的颜色:
- Change the variables inside the
:root
using JS or another CSS rule. This won't allow us to have different colors:
: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
中的定义将变得无用(或至少将成为默认值):
- Evaluate the variable again inside the needed element. In this case, we will lose any kind of flexibility and the definition inside
:root
will become useless (or at least will become the default value):
: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
选择器.这将确保我们的函数在所有级别都得到定义和评估.在某些复杂的情况下,这可能会产生一些不需要的结果
- Change the
:root
selector with the universal selector*
. This will make sure our function is defined and evaluated at all the levels. In some complex case, this may have some unwanted results
* {
--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 树中的最低点,尤其是在变量更改后(或在同一级别)
Considering this, we should always keep the evaluation at the lowest possible point in the DOM tree and especially after the variable changes (or at the same level)
这是我们不应该做的事
: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>
相关文章