Давайте предположим, что у нас есть веб-страница, на которой много элементов с текстом одного и того же цвета. Дизайнер создал фирменный стиль, руководство утвердило, мы начали верстать. Наш 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;
}
На практике
Скопированосоветует
Скопировано🛠 Можно эффективно использовать кастомные свойства при разработке дизайн-системы:
🛠 Кастомные свойства сильно упрощают жизнь, если нужны цветовые схемы или ночная тема:
🛠 Можно даже применять кастомные свойства в инлайновых стилях: