Menu

Переменные CSS: custom properties, :root и var()

Переменные CSS (custom properties) хранят значение в одном месте и переиспользуют его через var(). Разберем, как объявлять их в :root, ограничивать и переопределять, задавать значения по умолчанию, переключать темы через JavaScript и не попасть в ловушку невалидного значения.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Как объявить и использовать переменную CSS

Переменная CSS, официально custom property (пользовательское свойство), это свойство, имя которого начинается с --. Объявите ее один раз, обычно в :root, чтобы ее унаследовала вся страница, и читайте где угодно через var().

Измените --brand на #16a34a, и рамка карточки и кнопка поменяются вместе. В этом весь смысл: одно значение, одно место для правки. Переменные сочетаются и с calc(), как показывают боковые отступы кнопки.

Синтаксис

:root {
  --name: value;         /* declare */
}

.element {
  color: var(--name);                 /* use */
  color: var(--name, #111827);        /* use, with a fallback */
  padding: calc(var(--space) * 2);    /* compute with it */
}
ПравилоПодробности
ИмяНачинается с --, затем буквы, цифры, - или _. Регистр важен: --Brand это не --brand.
ЗначениеПочти что угодно: цвет, длина, список, строка. Оно не проверяется, пока его не используют.
Где объявлятьВ любом правиле. :root для глобальных, селектор компонента для локальных значений.
НаследованиеПользовательские свойства наследуются, поэтому дочерний элемент видит значения предков.
Где работает var()Только в значениях свойств, не в селекторах, не в именах свойств и не в условиях @media.

:root соответствует элементу <html>. Его используют вместо html, потому что специфичность у него как у класса, а по соглашению он обозначает «глобальные настройки».

Область видимости: переопределение переменной в компоненте

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

Варианты задают только переменную, а не саму рамку. Четвертый вариант добавляется одной строкой.

Значения по умолчанию

var(--name, fallback) использует запасное значение, когда переменная не определена ни на элементе, ни на одном предке. Все после первой запятой считается запасным значением, поэтому в нем самом могут быть запятые (var(--font, Georgia, serif)), и это может быть другой var().

Изменение переменных через JavaScript: переключатель темы

JavaScript может задать переменную на любом элементе через style.setProperty(). Задайте ее на document.documentElement (элемент <html>), и за ней последует вся страница. Чаще переключают класс, который переопределяет переменные:

Значение переменной читается через getComputedStyle(element).getPropertyValue('--text'). Учтите, что setProperty записывает встроенный стиль на <html>, который сильнее класса .dark, поэтому после нажатия второй кнопки цвет текста остается прежним в обеих темах, пока встроенное значение не удалят через root.style.removeProperty('--text').

Передача значений из HTML

Переменная в атрибуте style это самый чистый способ передать таблице стилей данные конкретного элемента. Дизайн остается в CSS, а HTML дает только число.

calc(var(--value) * 1%) превращает простое число в проценты. Переменные могут меняться и внутри медиазапроса: @media (min-width: 900px) { :root { --space: 20px; } } увеличивает на широких экранах все отступы, которые читают --space.

Ловушка невалидного значения

Браузер не может заранее знать, подходит ли значение переменной для свойства, которое ее использует. Если не подходит, свойство не откатывается к предыдущему объявлению в правиле. Оно становится невалидным на этапе вычисления значения и ведет себя так, будто ему задано unset: наследуемые свойства берут значение родителя, остальные свое начальное значение.

Текст наследует 16px от <body>, а border-width возвращается к начальному значению medium, которое браузеры рисуют как 3px. Без переменных невалидное объявление отбрасывается и предыдущее остается в силе; с переменными для этого уже поздно. Запасное значение не помогает, когда переменная определена, но неверна: оно только для неопределенной переменной.

Переменные CSS и переменные Sass

Переменные CSSПеременные Sass
Синтаксис--brand: #2563eb; и var(--brand)$brand: #2563eb;
Когда вычисляютсяВ браузере, на летуПри сборке, в результат не попадают
Разные значения у элементовДа, через наследованиеНет
Смена через класс или медиазапросДаНет
Смена из JavaScriptДаНет
Использование в селекторах и условиях mediaНетДа

Они работают вместе: многие проекты используют Sass для логики на этапе сборки и выдают CSS-переменные для всего, что должно меняться темой.

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

  • Забытые два дефиса. var(brand) и --brand, объявленная как -brand, не работают.
  • Переменная в медиазапросе. @media (min-width: var(--bp)) невалидно. В условиях media нужны буквальные значения.
  • Ожидание, что предыдущее объявление переживет невалидную переменную. Не переживет; смотрите ловушку выше.
  • Неправильное сочетание единиц. --gap: 10; и затем margin: var(--gap)px не дают 10px. Используйте calc(var(--gap) * 1px) или храните 10px.
  • Объявление не на том элементе. Переменную, объявленную на .card, не видят его соседи и родитель; общие значения объявляйте на :root.

Часто задаваемые вопросы

Как объявить переменную CSS?

Запишите внутри правила свойство, имя которого начинается с двух дефисов, для глобального значения обычно в :root: :root { --brand: #2563eb; }. Читайте ее где угодно через var(--brand), например color: var(--brand);.

Что такое :root в CSS?

:root это псевдокласс, который соответствует корневому элементу документа, в HTML-странице это <html>. Объявленные в нем переменные наследуют все элементы. Его специфичность как у класса, поэтому он сильнее простого селектора html.

Как задать значение по умолчанию для переменной CSS?

Передайте в var() второй аргумент: color: var(--accent, #2563eb);. Запасное значение используется, когда --accent не определена на элементе и его предках. Оно не используется, если переменная определена, но ее значение невалидно для свойства.

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

Вызовите setProperty у стиля элемента: document.documentElement.style.setProperty('--brand', '#16a34a'). Все правила с var(--brand) обновятся сразу. Текущее значение читается через getComputedStyle(el).getPropertyValue('--brand').

Чем переменные CSS отличаются от переменных Sass?

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

Учитывается ли регистр в именах переменных CSS?

Да. --Brand и --brand это две разные переменные, в отличие от имен обычных свойств вроде color, где регистр не важен.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ