Зачем нужны кастомные свойства и как они работают? — спрашивает наш зритель Андрей. Они пришли, чтобы навсегда изменить CSS. Давайте разберёмся.
В языках программирования есть переменные: вы что-нибудь один раз объявляете, присваиваете значение, а потом снова и снова используете. Если значение переменной меняется, то меняется везде. Похоже на местоимения в языке: из предложения или абзаца всегда понятно, кто «мы» или что за «оно», мы их как будто объявили раньше и наверняка переопределим потом.
Но это языки программирования, а что со стилями? Вообще, декларативная природа CSS не подразумевает никаких переменных и соавтор CSS Берт Бос очень против, почитайте. Но жизнь внесла свои коррективы в изначальную идею, и переменные в стилях появились — слишком уж удобно было. Но сначала в препроцессорах.
Как вообще работают препроцессоры? Вы пишете на каком-то языке, который внешне напоминает CSS, а иногда вообще не напоминает.
@mixin sass
@if &
&:hover
color: tomato
@else
a
color: plum
Потом это компилируется в настоящие стили. Переменные там — это такая сложная автозамена переменных на их значения. Sass, Less, Stylus, PostCSS-плагины — все они работают только так. Эти переменные существуют только в разработке, в браузере их уже нет.
.scss {
$variable: value;
color: $variable;
}
Если сравнить такое поведение с JavaScript, то становится очень обидно за CSS. В JS переменные живут прямо в браузере, их можно создавать и менять на лету. Тем не менее такие переменные и другие элементы программирования в CSS-препроцессорах получили огромную популярность. Уже почти не бывает больших проектов без препроцессоров.
К счастью, нашлись люди, недовольные такими куцыми переменными. После ряда черновиков и вариаций синтаксиса, Таб Аткинс написал спецификацию полноценных CSS-переменных, точнее, кастомных свойств. Эти переменные поддерживаются уже в 70% браузеров по миру и сильно меняют принцип написания стилей.
Кастомные кто? Объясняю. Помните, я говорил, что CSS не очень-то готов к переменным? Чтобы сохранить синтаксическую совместимость со старыми браузерами и не противоречить модели языка, было решено сделать не просто переменные с долларом в начале, а механизм создания собственных свойств для нужд разработчика. Ещё их переводят как «пользовательские» свойства, но с этим возникает путаница: кто здесь пользователь, а кто здесь разработчик? Сразу скажу, синтаксис у них немножко странный, но вы поймёте почему.
Например, у нас сейчас есть свойство box-shadow
, чтобы отбрасывать тень. А раньше его не было, оно появилось первым в браузере Safari в 2008 году. Но появилось не просто так, а как -webkit-box-shadow
, с префиксом, начинающимся с дефиса. То есть разработчики движка WebKit придумали своё свойство. Только потом, когда оно стало частью стандарта и появилось в других браузерах, префикс убрали.
.shady {
-webkit-box-shadow:
0 0 0 4px tomato;
box-shadow:
0 0 0 4px tomato;
}
Теперь вы тоже можете создавать собственные свойства, только не нужно указывать между дефисами название движка: дефис, дефис, название свойства. Давайте создадим свойство --box-shadow-color
и зададим ему значение tomato. Чтобы использовать это значение в коде, нужно передать его в функцию var()
.
.shady {
--box-shadow-color:
tomato;
box-shadow:
0 0 0 5px
var(--box-shadow-color);
}
Мы сейчас объявили новое свойство, которое потом можно повторно использовать снова и снова. А ещё свойства box-shadow-color
никогда не было в природе и чтобы менять тени, например, по наведению, приходилось переписывать box-shadow
целиком. А теперь по ховеру можно просто поменять значение переменной. Круто?
.shady {
--box-shadow-color:
tomato;
}
.shady:hover {
--box-shadow-color:
plum;
}
Если вы используете кастомное свойство, которое почему-то не было объявлено, то можно указать его значение по умолчанию, которое будет использовано в таком случае. Ваш компонент тогда можно будет настроить, но без настройки он не сломается.
.shady {
font-size:
var(
--font-size,
12px
);
}
Из-за того, что это кастомные свойства, а не просто доллары с автозаменой, они ведут себя как обычные свойства: наследуются вглубь для всех детей элемента и не видны между элементами-соседями. Чтобы переменную точно было видно во всём документе, её нужно задать самому корневому элементу html
, но лучше даже :root,
на случай если это корневой элемент svg.
:root {
--font-size: 12px;
--theme-color:
tomato;
}
Самое крутое, что переменные можно переопределять внутри медиавыражений. Например, если окно больше каких-то размеров, теперь не нужно копировать весь блок и менять его под новую ширину, достаточно поменять нужные кастомные свойства.
@media (min-width: 320px) {
.shady {
--font-size: 48px;
}
}
Кастомные свойства можно использовать даже внутри функции calc()
, которая посчитает результат выражения внутри. Уже не очень похоже на привычный CSS, правда? Стоит ли говорить, что все препроцессоры уже умерли от зависти, глядя на такое.
.shady {
font-size:
calc(
var(--font-size)
* 2
);
}
Ещё кастомные свойства становятся идеальным транспортом для данных между скриптами и стилями. Например, вы можете динамически считать координаты мыши в JS и пробрасывать их в кастомные свойства через setProperty
в нужный элемент.
element
.style
.setProperty(
'--pointer-left',
event.clientX
);
Дальше в стилях уже можно решить: использовать их в top
и left
или transform: translate()
. И наоборот: значение свойства можно получить в JS с помощью getPropertyValue.
И это я только кастомные свойства лапкой потрогал, дальше ещё куча интересного, что кардинально меняет работу со стилями. Читайте и смотрите дальше сами: статьи, видео и слайды в описании.
Кастомные свойства — это не border-radius
, который либо делает красиво, либо нет. Бросаться всё переделывать на них пока рано, вёрстка может сильно поломаться в браузерах, которые их не поддерживают. Но уже пришло время пробовать и уметь.