CSS-переменные: --имя, var() и тёмная тема на примере

опубликовано
обновлено
читать
≈ 4 мин
автор
среда и версия
CSS; пример и три правки проверены в HTML/CSS-песочнице Koddo (Chromium) 20 октября 2026.

Синий цвет кнопок повторяется в CSS двадцать раз, и чтобы сменить его, надо пройти по всему файлу. С переменными его пишут один раз, а ещё одной строкой меняют для отдельного блока: так делают тёмную тему или особую карточку.

CSS-переменная — свойство с именем, которое начинается с двух дефисов: --accent: #1d4ed8. Объявляют её обычно в :root, чтобы она была видна везде, а читают функцией var(--accent). Переменные наследуются, как цвет текста: блок может переопределить значение, и всё внутри него получит новое.

Пример: светлая и тёмная карточка из одной разметки

Открой пример в песочнице HTML/CSS ссылкой под вторым блоком: разметка попадёт во вкладку index.html, стили — в styles.css. Обе карточки сверстаны одинаково, а вторая стала тёмной потому, что у класса .dark свои значения четырёх переменных.

HTML:

<div class="cards">
  <article class="card">
    <h2>Светлая карточка</h2>
    <p>Цвета и отступы берутся из переменных.</p>
    <a class="button" href="#">записаться</a>
  </article>
  <article class="card dark">
    <h2>Тёмная карточка</h2>
    <p>Та же разметка: в ней переопределены четыре переменные.</p>
    <a class="button" href="#">записаться</a>
  </article>
</div>

CSS:

:root {
  --bg: #ffffff;
  --text: #1f2a44;
  --accent: #1d4ed8;
  --on-accent: #ffffff;
  --space: 1rem;
}

body {
  margin: 0;
  padding: var(--space);
  font-family: system-ui, sans-serif;
}

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--space);
}

.card {
  padding: calc(var(--space) * 1.5);
  border: 1px solid var(--border, #d6dbe4);
  border-radius: 0.75rem;
  background: var(--bg);
  color: var(--text);
}

.dark {
  --bg: #1f2a44;
  --text: #f2f4f8;
  --accent: #ffb703;
  --on-accent: #1f2a44;
}

.button {
  display: inline-block;
  padding: 0.5rem 1rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  text-decoration: none;
}

Объявить и прочитать: --имя и var()

Объявление. Переменную задают как обычное свойство, только имя начинается с --: --accent: #1d4ed8. Регистр важен: --accent и --Accent — разные переменные. Значение может быть любым: цвет, размер, целая строка вроде 0 2px 8px rgb(0 0 0 / 15%) для тени.

:root. Это корень документа, тот же html, только с более сильным селектором. Переменные в :root видны на всей странице, поэтому их обычно собирают там в одном месте.

Чтение. var(--accent) подставляет значение туда, где можно было бы написать само значение: background: var(--accent). Имя свойства переменной не бывает: var(--prop): red не сработает.

Запасное значение: var(--имя, запас)

Если переменной нет, var() возьмёт значение после запятой. В примере --border нигде не объявлена, поэтому рамка карточки берёт запасной #d6dbe4:

.card {
  border: 1px solid var(--border, #d6dbe4);
}

Без запаса свойство с необъявленной переменной считается недействительным, и элемент получит значение по умолчанию — например, прозрачный фон или унаследованный цвет. Запасное значение тоже может быть переменной: var(--border, var(--text)).

Наследование: переопределение в блоке

Переменная наследуется от родителя к детям, как цвет текста. Поэтому ей можно дать другое значение в любом блоке — и всё внутри блока получит его, а остальная страница останется прежней.

Переменные / 01

var() берёт ближайшее значение выше по дереву

Откуда кнопки двух карточек берут цвет --accentШаг 1: в :root объявлена переменная --accent со значением #1d4ed8. Шаг 2: у блока .dark та же переменная переопределена на #ffb703. Шаг 3: кнопка внутри обычной карточки ищет --accent выше по дереву и находит значение из :root — синий; кнопка внутри .dark находит значение .dark — жёлтый.:root.cards.card.card.darkкнопкакнопка01 / объявили в :root--accent: #1d4ed802 / переопределили в .dark--accent: #ffb703действует внутри блока03 / var(--accent)кнопка берёт ближайшеезначение выше по дереву
Переменная наследуется, как цвет текста: кнопка обычной карточки получает --accent из :root, а кнопка внутри .dark — значение, переопределённое этим блоком.

У класса .dark в примере своё --accent, поэтому кнопка внутри тёмной карточки жёлтая, а у светлой — синяя из :root. Сами правила .card и .button при этом одинаковые для обеих карточек: меняются только значения.

Тёмная тема и prefers-color-scheme

Тема — это набор переменных. Чтобы включить тёмную тему для всей страницы, а не для одной карточки, переменные переопределяют у :root в медиазапросе, который срабатывает, когда в системе выбрана тёмная тема:

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1f2a44;
    --text: #f2f4f8;
    --accent: #ffb703;
    --on-accent: #1f2a44;
  }
}

Переключатель на сайте делают так же: класс вроде .dark у html переопределяет те же переменные, а скрипт одной строкой ставит или убирает этот класс. Переменные цвета держи парами — фон и текст, акцент и текст на нём, — иначе при смене одной можно получить светлый текст на светлом фоне.

Переменные в calc()

Переменные с размерами удобно умножать: padding: calc(var(--space) * 1.5) даёт полтора базовых отступа. Поменяешь --space в :root — пересчитаются все отступы, которые от неё зависят, и сетка останется согласованной.

Число без единиц тоже можно хранить и превращать в размер: --columns: 3 и width: calc(100% / var(--columns)). А вот склеить единицы из текста не выйдет: var(--size)px не работает, нужно calc(var(--size) * 1px).

Чем это отличается от переменных Sass. Переменные Sass ($accent) существуют только при сборке: в готовом CSS вместо них уже стоят значения. CSS-переменные живут в браузере: их можно переопределить в блоке, в медиазапросе и даже поменять из JavaScript, и страница сразу перерисуется.

Три правки, чтобы закрепить

Открой пример в песочнице и перед каждой правкой предскажи результат:

  1. Поменяй в :root значение --accent на #2e7d32. Кнопка светлой карточки станет зелёной, а у тёмной останется жёлтой: у .dark своё значение.
  2. Убери из .dark строку --bg. Тёмная карточка побелеет, а текст в ней останется светлым и почти исчезнет: фон взялся из :root, а цвет текста — из .dark. Поэтому цвета переопределяют парами.
  3. Поставь в :root --space: 2rem. Все отступы вырастут вдвое: у страницы 32 пикселя, между карточками 32, внутри карточек 48 — они все считаются от одной переменной.

Переменные пригодятся в любой статье этого раздела — например, для отступов из статьи про margin и padding и цветов из статьи про шрифты и цвет текста.

Источники