
Механика предельно простая. Объявляете переменные в блоке :root — это псевдокласс, который указывает на корневой элемент документа (html), а значит, значения будут доступны на любой странице сайта:
:root {
--bg-color: #ffffff;
--text-color: #1f2d27;
--accent-color: #2e8b57;
--border-color: #dbe6e0;
}
Дальше вместо конкретных цветов в остальных стилях подставляете функцию var():
body {
background: var(--bg-color);
color: var(--text-color);
}
a {
color: var(--accent-color);
}
.card {
border: 1px solid var(--border-color);
}
На этом этапе разницы с обычными hex-кодами вроде бы никакой — разве что теперь цвет меняется в одном месте, а не ищется по всему файлу. Но настоящая сила custom properties раскрывается, когда нужно эти значения переопределить для другого состояния — например, для тёмной темы.
Переопределяются переменные ровно так же, как задавались, только уже в другом селекторе:
[data-theme="dark"] {
--bg-color: #1a1f1c;
--text-color: #e8efe9;
--accent-color: #5fbf8a;
--border-color: #2e3a34;
}
А переключение темы сводится к одной строчке JavaScript, которая ставит атрибут data-theme на <html>:
document.documentElement.setAttribute('data-theme', 'dark');
Всё остальное — вообще без дополнительного кода. Браузер сам пересчитывает var(--bg-color) во всех местах, где эта переменная используется, потому что CSS-переменные, в отличие от Sass-переменных, живут не на этапе компиляции, а прямо во время работы страницы в браузере. Sass-переменная — это просто текстовая подстановка перед сборкой, а custom property — реальное значение в дереве стилей, которое можно читать и менять в любой момент через JavaScript, и именно это отличие делает возможным мгновенное переключение темы без перезагрузки страницы и без повторной генерации CSS-файлов.
Есть и более простой сценарий без JS вообще — автоматическое подключение тёмной темы по системным настройкам пользователя через медиа-запрос prefers-color-scheme:
@media (prefers-color-scheme: dark) {
:root {
--bg-color: #1a1f1c;
--text-color: #e8efe9;
}
}
Такой вариант удобен как базовый уровень, но у него есть минус — пользователь не может вручную переключить тему на сайте, если его системная настройка не совпадает с тем, что ему хочется видеть именно на вашем ресурсе. На практике я обычно комбинирую оба подхода: prefers-color-scheme задаёт тему по умолчанию, а атрибут data-theme, выставляемый вручную через переключатель и запоминаемый в localStorage, позволяет пользователю переопределить системный выбор.
Отдельно стоит сказать про поддержку в старых браузерах — custom properties не работают в Internet Explorer вообще ни в каком виде, но для 2026 года это уже не проблема, доля IE в статистике посещений давно стремится к нулю. Все современные браузеры (Chrome, Firefox, Safari, Edge) поддерживают переменные без всяких полифиллов ещё с 2017 года.
Ещё один практический момент — переменные можно объявлять не только в :root, но и в любом селекторе, и тогда область их действия ограничивается этим блоком и его потомками. Это удобно для локальных «тем» внутри одного компонента — например, у карточки с акцентным цветом можно задать собственную переменную, не трогая глобальную палитру:
.card--warning {
--accent-color: #d9822b;
}
Всё, что внутри .card--warning использует var(--accent-color), автоматически подхватит оранжевый оттенок, а остальной сайт при этом останется зелёным.
Из подводных камней — если забыть указать запасное значение вторым аргументом в var(), а переменная почему-то не определена (опечатка в имени, например), свойство просто не применится вообще, без явной ошибки в консоли, которую было бы легко заметить. Спасает вторым параметром — var(--accent-color, #2e8b57) — тогда при отсутствии переменной браузер подставит запасной цвет, и вёрстка не «поедет» молча.









