</> Praktum

Главная / CSS / CSS-переменные

Урок · CSS

CSS-переменные: единые значения без копирования

Редакция PraktumОбновлено 14 минут на урок с практикойУровень: новичок

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

Коротко
  • Объявление: --имя: значение;, использование: var(--имя).
  • В :root — глобальные значения, в селекторе компонента — локальные.
  • Переменные наследуются потомками и могут переопределяться.
  • var(--x, запас) — запасное значение, если переменная не задана.
  • Тёмная тема — это переопределение тех же переменных.

Зачем этот урок сейчас

Фирменный синий встречается в стилях двадцать раз: в кнопках, ссылках, рамках. Дизайнер меняет оттенок — и начинается поиск по файлу. С переменными цвет, отступы и радиусы живут в одном месте, тёмная тема делается несколькими строками, а у компонентов появляются варианты без дублирования правил.

Объявление и использование

:root {
  --color-accent: #2a62d9;
  --color-text: #171923;
  --space-m: 16px;
  --radius: 12px;
}

.button {
  background: var(--color-accent);
  padding: 12px var(--space-m);
  border-radius: var(--radius);
}

a { color: var(--color-accent); }

Имя начинается с -- и чувствительно к регистру: --Accent и --accent — разные переменные. :root — корневой элемент страницы (тег html), поэтому объявленные там переменные доступны везде.

Наследование и область видимости

.card { --tone: #2f5d50; border-left: 4px solid var(--tone); }
.card.is-warning { --tone: #c7442f; }
.card .title { color: var(--tone); }  /* потомок видит переменную карточки */

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

Запасное значение

.hero {
  padding-top: var(--header-height, 64px);
  color: var(--hero-text, var(--color-text, #000));
}

Второй аргумент var() подставляется, если переменная не объявлена. Запасные значения можно вкладывать. Но запас не спасает от опечатки в значении: если --space-m: 16 px (с пробелом), переменная объявлена, а свойство, которое её использует, станет недействительным и вернётся к значению по умолчанию.

Светлая и тёмная тема

:root {
  --bg: #ffffff;
  --text: #171923;
  --muted: #617087;
  --line: #e5e8ef;
}

@media (prefers-color-scheme: dark) {
  :root { --bg: #14161f; --text: #e8eaf2; --muted: #a0a8bb; --line: #2a2f3d; }
}

[data-theme="dark"] { --bg: #14161f; --text: #e8eaf2; --muted: #a0a8bb; --line: #2a2f3d; }

body { background: var(--bg); color: var(--text); }

Компоненты читают var(--bg) и не знают, какая сейчас тема. Тема — это просто другой набор значений: по системной настройке через медиазапрос или по выбору человека через атрибут на html. Проверь, что в тёмной теме поменялись и фон, и текст, и рамки.

Как называть переменные

Имена переменных
ПлохоХорошоПочему
--blue--color-accentакцент может стать зелёным
--gray2--color-mutedимя говорит о роли
--16--space-mшкала размеров
--header--header-heightпонятно, что хранит

Называй по роли, а не по виду: когда в тёмной теме серый станет другим серым, имя --color-muted останется правдой.

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

:root { --space: 8px; }

.section { padding: calc(var(--space) * 4); }       /* 32px */
.grid    { gap: calc(var(--space) * 2); }           /* 16px */
.page    { padding-top: calc(var(--header-height, 64px) + 16px); }

Внутри calc() переменные складываются и умножаются. Так из одной базовой величины строится вся шкала отступов, и интерфейс выглядит согласованно.

Переменные и JavaScript

const root = document.documentElement;

root.style.setProperty('--color-accent', '#c7442f');            // задать
getComputedStyle(root).getPropertyValue('--color-accent').trim(); // прочитать

slider.addEventListener('input', () => {
  root.style.setProperty('--font-scale', slider.value);
});

JavaScript меняет переменные, и все стили, которые их читают, обновляются сами. Это удобно для темы, размера шрифта или величины с ползунка. Обычные состояния (открыто, выбрано) по-прежнему удобнее переключать классами.

Где переменные не работают

Переменную нельзя использовать в условии медиазапроса (@media (min-width: var(--md)) не сработает) и в имени свойства или селектора. Значение подставляется как есть, поэтому var(--size)px не превратится в «16px» — нужно хранить единицы в самой переменной или писать calc(var(--size) * 1px).

CSS-переменные или переменные Sass

CSS-переменные

Живут в браузере: наследуются, переопределяются в компонентах и медиазапросах, меняются из JavaScript.

Переменные Sass

Исчезают при сборке, подставляясь значением. Нельзя поменять в браузере или переопределить для потомков.

Частые ошибки

  • Называют переменные по цвету: --blue2.
  • Объявляют переменную в блоке, а читают в соседнем, который её не наследует.
  • Пишут var(--size)px и ждут единицы измерения.
  • Ставят переменную в условие медиазапроса.
  • Выносят в переменные значения, которые нигде не повторяются.

Доступность

Переменные упрощают доступность: контрастную или тёмную тему можно сделать переопределением набора цветов. Проверяй контраст текста и фона в каждой теме — не ниже 4.5:1 для основного текста. Если позволяешь менять размер шрифта переменной, задавай его в rem, чтобы учитывались и настройки браузера.

Поддержка браузерами

CSS-переменные поддерживаются всеми актуальными браузерами с 2017 года. Правило @property, которое задаёт переменной тип и делает её анимируемой, тоже доступно в современных версиях браузеров.

Практика

Создай переменные для фона, текста, акцента, радиуса и базового отступа. Сделай из них карточку и кнопку. Добавь вариант карточки .card--warning, который меняет только переменную акцента, и тёмную тему по атрибуту data-theme="dark" на html.

Показать решение
:root {
  --bg: #fff; --text: #171923; --accent: #2a62d9;
  --radius: 12px; --space: 8px;
}
[data-theme="dark"] { --bg: #14161f; --text: #e8eaf2; --accent: #7aa2ff; }

body { background: var(--bg); color: var(--text); }
.card {
  padding: calc(var(--space) * 3);
  border-radius: var(--radius);
  border-left: 4px solid var(--accent);
}
.card--warning { --accent: #c7442f; }
.button {
  background: var(--accent);
  color: #fff;
  padding: var(--space) calc(var(--space) * 2);
  border-radius: var(--radius);
}

Открыть песочницу

Частые вопросы

Где объявлять CSS-переменные?

Глобальные — в :root, локальные — в селекторе компонента. Переменная доступна элементу и всем его потомкам.

Что будет, если переменная не объявлена?

Подставится запасное значение из второго аргумента var(). Если запаса нет, свойство вернётся к значению по умолчанию.

Можно ли использовать переменную в медиазапросе?

Внутри блока медиазапроса — да, в самом условии — нет.

Как изменить CSS-переменную из JavaScript?

document.documentElement.style.setProperty('--имя', 'значение'). Все стили, которые читают переменную, обновятся.

Чем CSS-переменные лучше переменных Sass?

Они работают в браузере: наследуются, переопределяются для отдельных компонентов и тем, меняются из JavaScript. Переменные Sass исчезают при сборке.

Источники