Это немного сложно, но в вашем случае вы оценили пользовательское свойство --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-*
будет определяться правильно для каждого случая.
С спецификацией :
На подставить переменную () в значении свойства:
- Если пользовательское свойство, названное первым аргументом функции var (), испорчено анимацией, а функция var () используется в свойстве animation или в одном из его длинных строк, обработайте пользовательское свойствокак имеющее начальное значение для остальной части этого алгоритма.
- Если значение настраиваемого свойства, названного первым аргументом функции var (), отличается от начального значения, замените функцию var () назначение соответствующего пользовательского свойства.В противном случае,
- , если функция var () имеет запасное значение в качестве второго аргумента, замените функцию var () на запасное значение.Если в резерве есть какие-либо ссылки на var (), замените их.
- В противном случае свойство, содержащее функцию 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 переменных, определенных на уровне :root
, но нет.Мы не можем этого сделать, и приведенный выше код такой же, как этот:
: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
, поэтому мы уже можем подставить их значения.
В такой ситуации у нас есть 2 возможности:
- Изменить переменные внутри
: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>
Учитывая это, мы всегда должны сохранять оценку минимально возможной в дереве 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>