Переменные CSS, более точно известные как пользовательские свойства CSS, появляются в Chrome 49. Они могут быть полезны для сокращения повторений в CSS, а также для мощных эффектов времени выполнения, таких как переключение тем и потенциальное расширение/полизаполнение будущих функций CSS.
CSS-беспорядок
При проектировании приложения принято откладывать набор фирменных цветов, которые будут повторно использоваться для сохранения единообразия внешнего вида приложения. К сожалению, многократное повторение этих цветовых значений в CSS не только рутина, но и подвержено ошибкам. Если в какой-то момент один из цветов нужно будет изменить, вы можете отбросить осторожность и «найти и заменить» все, но в достаточно большом проекте это может легко стать опасным.
В последнее время многие разработчики обратились к препроцессорам CSS, таким как SASS или LESS, которые решают эту проблему с помощью переменных препроцессора. Хотя эти инструменты значительно повысили производительность разработчиков, переменные, которые они используют, страдают от серьезного недостатка, который заключается в том, что они статичны и не могут быть изменены во время выполнения. Добавление возможности изменения переменных во время выполнения не только открывает дверь таким вещам, как динамическое тематизирование приложений, но также имеет серьезные последствия для адаптивного дизайна и потенциала для полифилла будущих функций CSS. С выпуском Chrome 49 эти возможности теперь доступны в форме пользовательских свойств CSS.
Пользовательские свойства в двух словах
Пользовательские свойства добавляют две новые функции в наш набор инструментов CSS:
- Возможность для автора присваивать произвольные значения свойству с выбранным им именем.
- Функция
var()
, которая позволяет автору использовать эти значения в других свойствах.
Вот небольшой пример для демонстрации.
:root {
--main-color: #06c;
}
#foo h1 {
color: var(--main-color);
}
--main-color
— это определенное автором пользовательское свойство со значением #06c. Обратите внимание, что все пользовательские свойства начинаются с двух тире.
Функция var()
извлекает и заменяет себя значением пользовательского свойства, в результате чего получается color: #06c;
Если пользовательское свойство определено где-то в таблице стилей, оно должно быть доступно функции var
.
Синтаксис может показаться немного странным на первый взгляд. Многие разработчики спрашивают: «Почему бы просто не использовать $foo
для имен переменных?» Подход был специально выбран, чтобы быть максимально гибким и потенциально допускать макросы $foo
в будущем. Для предыстории вы можете прочитать этот пост от одного из авторов спецификации, Таба Аткинса.
Синтаксис пользовательских свойств
Синтаксис пользовательского свойства прост.
--header-color: #06c;
Обратите внимание, что пользовательские свойства чувствительны к регистру, поэтому --header-color
и --Header-Color
— это разные пользовательские свойства. Хотя они могут показаться простыми на первый взгляд, допустимый синтаксис для пользовательских свойств на самом деле довольно разрешительный. Например, следующее является допустимым пользовательским свойством:
--foo: if(x > 5) this.width = 10;
Хотя это не было бы полезно как переменная, так как это было бы недействительно в любом обычном свойстве, оно потенциально может быть прочитано и обработано JavaScript во время выполнения. Это означает, что пользовательские свойства имеют потенциал для разблокировки всех видов интересных методов, которые в настоящее время невозможны с сегодняшними препроцессорами CSS. Так что если вы думаете: « зеваю, у меня есть SASS, так что кого это волнует…», то взгляните еще раз! Это не те переменные, с которыми вы привыкли работать.
каскад
Пользовательские свойства следуют стандартным правилам каскадирования, поэтому вы можете определить одно и то же свойство на разных уровнях специфичности.
:root { --color: blue; }
div { --color: green; }
#alert { --color: red; }
* { color: var(--color); }
<p>I inherited blue from the root element!</p>
<div>I got green set directly on me!</div>
<div id="alert">
While I got red set directly on me!
<p>I’m red too, because of inheritance!</p>
</div>
Это означает, что вы можете использовать пользовательские свойства внутри медиа-запросов для поддержки адаптивного дизайна. Одним из вариантов использования может быть расширение полей вокруг основных секционных элементов по мере увеличения размера экрана:
:root {
--gutter: 4px;
}
section {
margin: var(--gutter);
}
@media (min-width: 600px) {
:root {
--gutter: 16px;
}
}
Важно отметить, что приведенный выше фрагмент кода невозможен с использованием современных препроцессоров CSS, которые не могут определять переменные внутри медиазапросов. Наличие этой возможности открывает большой потенциал!
Также возможно иметь пользовательские свойства, которые получают свое значение из других пользовательских свойств. Это может быть чрезвычайно полезно для тематизации:
:root {
--primary-color: red;
--logo-text: var(--primary-color);
}
Функция var()
Чтобы получить и использовать значение пользовательского свойства, вам нужно будет использовать функцию var()
. Синтаксис функции var()
выглядит следующим образом:
var(<custom-property-name> [, <declaration-value> ]? )
Где <custom-property-name>
— это имя определенного автором пользовательского свойства, например --foo
, а <declaration-value>
— это резервное значение, которое будет использоваться, когда указанное пользовательское свойство недействительно. Резервные значения могут быть списком, разделенным запятыми, который будет объединен в одно значение. Например var(--font-stack, "Roboto", "Helvetica");
определяет резервное значение "Roboto", "Helvetica"
. Имейте в виду, что сокращенные значения, такие как используемые для полей и отступов, не разделены запятыми, поэтому соответствующий резервный вариант для отступов будет выглядеть следующим образом.
p {
padding: var(--pad, 10px 15px 20px);
}
Используя эти резервные значения, автор компонента может написать защитные стили для своего элемента:
/* In the component’s style: */
.component .header {
color: var(--header-color, blue);
}
.component .text {
color: var(--text-color, black);
}
/* In the larger application’s style: */
.component {
--text-color: #080;
/* header-color isn’t set,
and so remains blue,
the fallback value */
}
Этот метод особенно полезен для темизации веб-компонентов, использующих Shadow DOM, поскольку пользовательские свойства могут пересекать границы тени. Автор веб-компонента может создать начальный дизайн с использованием резервных значений и раскрыть «крючки» темизации в форме пользовательских свойств.
<!-- In the web component's definition: -->
<x-foo>
#shadow
<style>
p {
background-color: var(--text-background, blue);
}
</style>
<p>
This text has a yellow background because the document styled me! Otherwise it
would be blue.
</p>
</x-foo>
/* In the larger application's style: */
x-foo {
--text-background: yellow;
}
При использовании var()
есть несколько подводных камней, на которые следует обратить внимание. Переменные не могут быть именами свойств. Например:
.foo {
--side: margin-top;
var(--side): 20px;
}
Однако это не эквивалентно установке margin-top: 20px;
. Вместо этого второе объявление недействительно и выдается как ошибка.
Аналогично, вы не можете (наивно) создать значение, часть которого предоставляется переменной:
.foo {
--gap: 20;
margin-top: var(--gap)px;
}
Опять же, это не эквивалентно установке margin-top: 20px;
. Чтобы построить значение, вам нужно кое-что еще: функция calc()
.
Создание значений с помощью calc()
Если вы никогда раньше с этим не работали, функция calc()
— это удобный небольшой инструмент, позволяющий выполнять вычисления для определения значений CSS. Она поддерживается всеми современными браузерами и может быть объединена с пользовательскими свойствами для создания новых значений. Например:
.foo {
--gap: 20;
margin-top: calc(var(--gap) * 1px); /* niiiiice */
}
Работа с пользовательскими свойствами в JavaScript
Чтобы получить значение пользовательского свойства во время выполнения, используйте метод getPropertyValue()
вычисляемого объекта CSSStyleDeclaration.
/* CSS */
:root {
--primary-color: red;
}
p {
color: var(--primary-color);
}
<!-- HTML -->
<p>I’m a red paragraph!</p>
/* JS */
var styles = getComputedStyle(document.documentElement);
var value = String(styles.getPropertyValue('--primary-color')).trim();
// value = 'red'
Аналогично, чтобы задать значение пользовательского свойства во время выполнения, используйте метод setProperty()
объекта CSSStyleDeclaration
.
/* CSS */
:root {
--primary-color: red;
}
p {
color: var(--primary-color);
}
<!-- HTML -->
<p>Now I’m a green paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'green');
Вы также можете задать значение пользовательского свойства, чтобы оно ссылалось на другое пользовательское свойство во время выполнения, используя функцию var()
при вызове setProperty()
.
/* CSS */
:root {
--primary-color: red;
--secondary-color: blue;
}
<!-- HTML -->
<p>Sweet! I’m a blue paragraph!</p>
/* JS */
document.documentElement.style.setProperty('--primary-color', 'var(--secondary-color)');
Поскольку пользовательские свойства могут ссылаться на другие пользовательские свойства в ваших таблицах стилей, вы можете себе представить, к каким интересным эффектам во время выполнения это может привести.
Поддержка браузера
В настоящее время Chrome 49, Firefox 42, Safari 9.1 и iOS Safari 9.3 поддерживают пользовательские свойства.
Демо
Попробуйте пример , чтобы увидеть все интересные приемы, которые теперь можно использовать благодаря настраиваемым свойствам.
Дальнейшее чтение
Если вам интересно узнать больше о пользовательских свойствах, Филип Уолтон из команды Google Analytics написал руководство о том, почему он так рад появлению пользовательских свойств , а следить за их развитием в других браузерах вы можете на сайте chromestatus.com .