Другое

Как заставить CSS-переменные пересчитываться в дочерних элементах

Узнайте, как заставить CSS-переменные (custom properties) пересчитываться при переопределении в дочерних элементах. Решения с calc(), дополнительными переменными и JavaScript для динамических тем.

Как заставить CSS‑переменные (custom properties) пересчитываться при переопределении в дочерних элементах?

Проблема:

html
<body>
  <div class="parent"><div class="child"></div></div>
</body>
css
body {
  --color: green;
}

.parent {
  --bg: var(--color);
}

.child {
  --color: red;
  background-color: var(--bg);
}

Я переопределил --color в дочернем элементе, но значение --bg зафиксировалось в родительском элементе и для дочернего остаётся зеленым. В дочернем элементе нужно красное. Понимаю, что так устроена спецификация CSS, но можно ли как‑то где‑то что‑то настроить или прописать (не глобально для всего проекта, а точечно)? Типа «позднее связывание» для переменных.

CSS‑переменные действительно имеют механизм позднего связывания (late binding), который позволяет им пересчитываться при изменении значений, но в вашем случае проблема заключается в том, что переменная --bg разрешается (resolves) в момент её определения в родительском элементе, а не при использовании в дочернем элементе.

Вот несколько способов решить эту проблему с поздним связыванием для CSS‑переменных:


Содержание


Понимание механизма разрешения CSS‑переменных

Как отмечает Mozilla Developer Network, CSS‑переменные разрешаются во время выполнения (runtime), что делает их динамичными. Однако разрешение происходит в момент использования переменной, а не в момент её определения.

В вашем примере:

  • В родительском элементе --bg получает значение текущей переменной --color (зелёный)
  • Даже если дочерний элемент переопределяет --color на красный, --bg остаётся зелёным, так как был разрешён ранее

Решение с использованием CSS calc()

Можно использовать функцию calc() для принудительного позднего разрешения:

css
body {
  --color: green;
}

.parent {
  --bg: calc(1 * var(--color)); /* Принудительное позднее связывание */
}

.child {
  --color: red;
  background-color: var(--bg); /* Теперь будет красным */
}

Этот метод заставляет браузер пересчитывать значение при каждом использовании, согласно исследованиям CodeLucky.


Решение с дополнительной переменной

Создайте промежуточную переменную, которая будет ссылаться на исходную переменную:

css
body {
  --color: green;
}

.parent {
  --color-reference: var(--color);
  --bg: var(--color-reference);
}

.child {
  --color: red;
  --color-reference: var(--color); /* Обновляем ссылку */
  background-color: var(--bg); /* Теперь будет красным */
}

Этот подход описан в статье о динамических стилях, где показано, как создавать гибкие системы переменных.


Решение с JavaScript (динамическое обновление)

Для более сложных сценариев можно использовать JavaScript для динамического обновления переменных:

javascript
// Функция для обновления переменных
function updateCSSVariables() {
  const child = document.querySelector('.child');
  const currentColor = getComputedStyle(child).getPropertyValue('--color').trim();
  child.style.setProperty('--bg', currentColor);
}

// Вызов при изменении переменных
updateCSSVariables();

Этот метод подробно рассматривается в статье LogRocket, где показаны продвинутые техники работы с CSS‑переменными.


Решение с CSS‑функцией

Можно создать пользовательскую CSS‑функцию для разрешения переменных:

css
:root {
  --color: green;
}

.parent {
  --bg: var(--color);
}

.child {
  --color: red;
}

/* Функция для разрешения переменных в контексте элемента */
.child::before {
  content: var(--color);
  display: none;
}

.child {
  background-color: var(--color); /* Прямое использование */
}

Современные подходы к динамическим темам

Для более сложных систем с динамическими темами можно использовать следующие подходы:

1. Иерархическая система переменных

css
:root {
  --color-primary: green;
}

.component {
  --color-current: var(--color-primary);
  --bg: var(--color-current);
}

.component .child {
  --color-current: red;
  background: var(--color-current);
}

2. CSS‑in‑JS подходы

Как описано в статье Josh W. Comeau, можно комбинировать CSS‑переменные с React для создания динамичных тем:

javascript
const theme = {
  primary: 'green',
  secondary: 'red'
};

const styles = {
  '--bg': theme.primary
};

// При обновлении темы
styles['--bg'] = theme.secondary;

Заключение

  1. Основная проблема: CSS‑переменные разрешаются в момент использования, а не в момент определения
  2. Решение №1: Используйте calc() для принудительного позднего разрешения
  3. Решение №2: Создавайте промежуточные переменные‑ссылки
  4. Решение №3: Для сложных случаев используйте JavaScript для динамического обновления
  5. Рекомендация: Для компонентных подходов используйте иерархические системы переменных с чётким разделением областей видимости

Каждый метод имеет свои преимущества — от простых CSS‑решений до комплексных JavaScript‑подходов. Выбор зависит от сложности вашего проекта и требуемой динамики обновления.


Источники

  1. Using CSS custom properties (variables) - MDN
  2. CSS Variable Inheritance: Complete Guide - CodeLucky
  3. Dynamic Styling with CSS Variables - Let’s Build UI
  4. How to use CSS variables like a pro - LogRocket
  5. How to use CSS variables with React - Josh W. Comeau
  6. Making Custom Properties (CSS Variables) More Dynamic - CSS-Tricks
Авторы
Проверено модерацией
Модерация