Давайте предположим, что у нас есть веб-страница, на которой много элементов с текстом одного и того же цвета. Дизайнер создал фирменный стиль, руководство утвердило, мы начали верстать. Наш CSS мог бы выглядеть примерно так:
.header-primary { font-size: 2em; color: #18191C; margin-bottom: .5em;}.header-secondary { font-size: 1.6em; color: #18191C;}.text { font-family: "Open Sans", sans-serif; color: #18191C; margin-top: 0;}.form-input { font-size: 1em; color: #18191C; padding-top: 4px; padding-bottom: 4px;}
.header-primary { font-size: 2em; color: #18191C; margin-bottom: .5em; } .header-secondary { font-size: 1.6em; color: #18191C; } .text { font-family: "Open Sans", sans-serif; color: #18191C; margin-top: 0; } .form-input { font-size: 1em; color: #18191C; padding-top: 4px; padding-bottom: 4px; }
Конкретный оттенок чёрного #18191
используется по всей странице в совершенно разных элементах: заголовках, тексте, кнопках, полях ввода. Кажется, что это не должно создавать никаких проблем, но на самом деле есть ряд неудобств, которых хотелось бы избежать.
Во-первых, если завтра по какой-то причине нужно будет немного изменить оттенок чёрного, придётся это делать во многих местах.
Во-вторых, приходится копировать и вставлять HEX-значение цвета, ну или запоминать первые несколько символов, чтобы текстовый редактор сумел нам подсказать.
Все эти неудобства уходят, если использовать CSS-переменные. Чаще их называют кастомные свойства.
Что это и как пишется?
СкопированоКастомное свойство — это произвольное свойство с определённым значением. Оно отличается от стандартного CSS-свойства способом записи. Чтобы применить кастомное свойство, нужно передать его в CSS-функцию var
.
Стандартное свойство:
.list-item { margin-left: 10px;}.list-item .link { margin-left: 10px;}
.list-item { margin-left: 10px; } .list-item .link { margin-left: 10px; }
Кастомное свойство:
.list { --element-gap: 10px;}.list-item { margin-left: var(--element-gap);}.list-item .link { margin-left: var(--element-gap);}
.list { --element-gap: 10px; } .list-item { margin-left: var(--element-gap); } .list-item .link { margin-left: var(--element-gap); }
Кастомных свойств не существует в спецификации CSS. По способам применения они больше всего похожи на переменные в языках программирования. Если мы определили кастомное свойство, то в дальнейшем можно его переиспользовать сколько угодно раз.
Наследование кастомных свойств
СкопированоКак и обычные наследуемые свойства (например, font
), кастомные свойства наследуются вниз по дереву. Определив переменную в родительском элементе, мы сможем переиспользовать её в любом дочернем элементе:
<div class="cards"> <div class="card"> <h2 class="card-header">Тариф «Бесплатный»</h2> <ul class="benefits"> <li class="benefits-item">1 пользователь</li> <li class="benefits-item">2 ГБ трафика</li> </ul> </div> <div class="card card--primary"> <h2 class="card-header">Тариф «Популярный»</h2> <ul class="benefits"> <li class="benefits-item">До 5 пользователей</li> <li class="benefits-item">20 ГБ трафика</li> </ul> </div></div>
<div class="cards"> <div class="card"> <h2 class="card-header">Тариф «Бесплатный»</h2> <ul class="benefits"> <li class="benefits-item">1 пользователь</li> <li class="benefits-item">2 ГБ трафика</li> </ul> </div> <div class="card card--primary"> <h2 class="card-header">Тариф «Популярный»</h2> <ul class="benefits"> <li class="benefits-item">До 5 пользователей</li> <li class="benefits-item">20 ГБ трафика</li> </ul> </div> </div>
.cards { --main-color: #E6E6E6;}.card-header, .benefits-item { color: var(--main-color);}.card--primary { --main-color: black;}
.cards { --main-color: #E6E6E6; } .card-header, .benefits-item { color: var(--main-color); } .card--primary { --main-color: black; }
В примере мы переопределяем значение переменной для карточки с классом .card
, и все дочерние элементы меняют цвет. В этом и кроется основная мощь CSS-переменных. Изменяем значение в одном месте, а затрагиваем все места, где используется переменная.
Но что, если мы заранее не знаем, какой будет вложенность элементов? Можно задать кастомное свойство корневому элементу страницы <html>
, и тогда оно гарантированно будет доступно в каждом элементе страницы. Но обычно для этих целей используют псевдокласс :root
, который является псевдонимом для <html>
:
:root { --gap-small: 10px; --gap-medium: 20px;}
:root { --gap-small: 10px; --gap-medium: 20px; }
В первом примере цвет #18191
используется в самых разных элементах страницы. Мы можем назначить этот цвет кастомному свойству с осмысленным названием и дальше везде использовать именно это свойство. Очень удобно, ведь запомнить название свойства проще, чем HEX-код цвета:
:root { --text-color: #18191C;}.header-primary { font-size: 2em; color: var(--text-color); margin-bottom: .5em;}.header-secondary { font-size: 1.6em; color: var(--text-color);}.text { font-family: "Open Sans", sans-serif; color: var(--text-color); margin-top: 0;}.form-input { font-size: 1em; color: var(--text-color); padding-top: 4px; padding-bottom: 4px;}
:root { --text-color: #18191C; } .header-primary { font-size: 2em; color: var(--text-color); margin-bottom: .5em; } .header-secondary { font-size: 1.6em; color: var(--text-color); } .text { font-family: "Open Sans", sans-serif; color: var(--text-color); margin-top: 0; } .form-input { font-size: 1em; color: var(--text-color); padding-top: 4px; padding-bottom: 4px; }
Обратите внимание: кастомные свойства, объявленные в :root
, тоже при необходимости могут быть переопределены:
:root { --main-color: #18191C;}.article-promo { --main-color: #272822;}
:root { --main-color: #18191C; } .article-promo { --main-color: #272822; }
Запасные значения
СкопированоЕсли по какой-то причине значение переменной не определено, мы можем передавать в функцию var
второй параметр, который станет «запасным» значением. По аналогии со свойством font
. Если не найдено первое значение, браузер будет подставлять следующее:
.section-title { color: var(--primary-color, #222);}
.section-title { color: var(--primary-color, #222); }
В качестве запасного значения может быть передана функция var
, которая в свою очередь также может иметь запасное значение:
.section-title { color: var(--primary-color, var(--black, #222));}
.section-title { color: var(--primary-color, var(--black, #222)); }
Корректность использования
СкопированоУ стандартных CSS-свойств типы значений предопределены, поэтому браузер понимает, правильно ли мы употребляем значение.
Используем HEX-запись цвета для свойства color
. Это правильно.
.valid-value { color: #272822;}
.valid-value { color: #272822; }
Используем размерную величину для свойства color
. Это неправильно.
.invalid-value { color: 10px;}
.invalid-value { color: 10px; }
У кастомных свойств всё иначе. Значения вычисляются в браузере непосредственно перед отрисовкой страницы. Браузер заранее не знает, в каком месте будет применено кастомное свойство, поэтому по умолчанию считает любую переменную корректной. И только после подстановки значения свойству браузер узнаёт, правильно ли мы его применили. Для такого поведения есть причины, рассмотрим пример:
:root { --big-header: 20px;}.promo-header { color: var(--big-header);}
:root { --big-header: 20px; } .promo-header { color: var(--big-header); }
В этом примере браузер подставляет значение переменной -
(20px
) в качестве значения свойства color
, но это не имеет смысла. В такой ситуации браузер делает две вещи:
- Проверяет, является ли свойство наследуемым. Если да, то значение для него ищется выше по дереву.
- Если свойство не наследуемое или значение не найдено выше по дереву, то берётся начальное значение по умолчанию (
initial
). Для свойстваcolor
у заголовка это будетblack
.
Использование в JavaScript
СкопированоВ JavaScript значения кастомных свойств используются точно так же, как и значения стандартных CSS-свойств.
Чтобы получить значение:
element.style.getPropertyValue("--main-color")
element.style.getPropertyValue("--main-color")
Чтобы задать значение:
element.style.setProperty("--translate", `${currentScroll}px`)
element.style.setProperty("--translate", `${currentScroll}px`)
Подсказки
СкопированоКастомные свойства можно использовать в любых других функциях. Например, в функции calc
.
.logo { display: inline-block; width: calc(var(--size, 1) * 15px); height: calc(var(--size, 1) * 15px);}.logo--small { --size: 2;}.logo--medium { --size: 3;}.logo--big { --size: 4;}
.logo { display: inline-block; width: calc(var(--size, 1) * 15px); height: calc(var(--size, 1) * 15px); } .logo--small { --size: 2; } .logo--medium { --size: 3; } .logo--big { --size: 4; }
В этом примере мы задали значение по умолчанию, равное 1
. Если будет использоваться только класс .logo
, браузер установит -
. Если будет применён один из классов-модификаторов, значение -
будет переопределено, и ширина и высота элемента будут пересчитаны благодаря использованию calc
.
А вот так можно применить CSS-переменную в функции linear
.
.element { --angle: 45deg; background-image: linear-gradient(var(--angle), #235ad1, #23d1a8);}.element--inverted { --angle: -45deg;}
.element { --angle: 45deg; background-image: linear-gradient(var(--angle), #235ad1, #23d1a8); } .element--inverted { --angle: -45deg; }
На практике
Скопированосоветует Скопировано
🛠 Можно эффективно использовать кастомные свойства при разработке дизайн-системы:
🛠 Кастомные свойства сильно упрощают жизнь, если нужны цветовые схемы или ночная тема:
🛠 Можно даже применять кастомные свойства в инлайновых стилях: