Всем привет, тема переменных в CSS давно ходит по интернету, однако не все знают о том, что это такое, да и сама технология не так давно вышла в релиз. И хоть использовать её во многих случаях рановато, уже пора понимать что она из себя представляет и как ею пользоваться. Давайте попробуем разобраться с технологией вместе. Обращу ваше внимание, что эта статья для тех, кто не знает о CSS переменных (кастомных свойствах) или только слышал о них. Если вы знакомы и умеете работать с данной фичей, то вам данная статья будет не интересна.
Итак, тема с переменными в стилях уже затерта до дыр, т.к. они давным давно существуют в препроцессорах. Это удобно, я уже плохо представляю себе написание стилей без возможности сохранить где-то определенное значение (цвет, величину, название шрифта, тип маркера у списка, всё что может придти в голову...). Однако препроцессоры не могут дать нам той гибкости, которую дают нативные переменные в CSS, и скоро вы поймете, почему.
Для начала нужно понять, как объявлять и использовать переменные. Переменные объявляются в селекторах:
:root {
--body-background: #ccc;
}
body {
background-color: var(--body-background);
}
Как видно из листинга выше, переменные объявляются двумя дефисами перед именем:
--variable-name
Чтобы использовать переменную, необходимо воспользоваться функцией var. Она имеет 2 параметра. Это, естественно, имя переменной, а вторым необязательным параметром идёт значение свойства, которое необходимо использовать в случае отсутствия переменной.
На этом набор новых возможностей с приходом переменных, разумеется, не заканчивается. Имея переменные в арсенале CSS, мы получаем большую гибкость в написании стилей. Например, теперь чтобы составить медиазапрос для экранов <320px в ширину, не нужно переопределять свойство целиком. Достаточно изменить значение переменной. Т.е.
.title {
--wrapper-width: 50%;
width: var(--wrapper-width);
}
@media (max-width: 320px) {
--wrapper-width: 100%;
}
Всё! Этого достаточно, чтобы свойство width изменило свое значение!
Если CSS способен отслеживать изменения своих переменных, это значит, что с этим можно взаимодействовать различными способами.
Что насчёт JavaScript?
Управляя аттрибутом style, можно изменить стиль, прибегая к минимальным затратам усилий. Приведу грубый пример на React.
.title {
--background: blue;
background-color: var(--background);
}
changeColor() {
this.setState({
style: {'--background': 'green'}
});
}
<div className="title" style={this.state.style} onClick={this.changeColor.bind(this)}>Title</div>
Теперь по клику на элемент с классом title будет меняться цвет фона у элемента. Круто? Ещё бы! Не нужно добавлять новый класс, переопределять свойство или делать другие действия, способствующие изменению фонового цвета у элемента.
--background
Используя переменные, изменять css извне стало проще, методов использования можно придумать массу, а мы пойдем дальше.
Области видимости
Нужно сказать пару слов об области видимости CSS переменных, здесь всё просто. Объявленная переменная доступна всем селекторам дочерних элементов данного селектора. Т.е. в листинге ниже использовать переменную --b в тэге html будет нельзя. А вот переменная --a в body и всех дочерних элементах будет работать без проблем (если её конечно не переопределят где-то ниже).
html {
--a: #ccc;
}
body {
--b: #a3a3a3;
}
(я знаю, что цвета в примерах скучные, но я плохо помню цвета по hex-коду :))
Переменные и calc
Как и любое числовое значение свойства, вы можете использовать переменную в функции calc.
.title {
--title-width: 300px;
width: calc(var(--title-width) + 150px);
}
Круто! Особенно если учесть что переменную --title-width, можно менять как внутри CSS, так и извне.
Заметьте, что величину мы обязаны положить в переменную. Дописать px, %, rem и т.д. к вызванной переменной у нас не получится. Однако ничто не мешает нам умножить с помощью функции calc значение на единицу в необходимой нам величине.
.title {
--title-width: 300;
/* так не сработает */
width: var(--title-width)px;
/* так сработает */
width: calc(var(--title-width) * 1px);
}
В заключение
CSS переменные дают много гибкости, это мощный инструмент, который может быть очень полезен в ряде случаев. Однако спешить его применять в боевых проектах я не рекомендую. Если мы заглянем на caniuse, то увидим что IE вообще не поддерживает данную технологию, а Edge частично.
Комментарии (34)
almassar
04.07.2017 11:39+3У меня в голове ну укладывается, почему такая мощная организация как Microsoft, не может сделать нормальный современный браузер?.. Тем более что многие стандарты по CSS разрабатывали их сотрудники.
msts2017
04.07.2017 13:21У меня в голове не укладывается как вообще кому-то пришло в голову имя переменной начинать с дефисов, ведь никакой необходимости отделять (как выше комментировано) их нету, наоборот весь стиль это набор переменных, на месте Microsoft из принципа такое говно не пропустил.
PHmaster
04.07.2017 13:58никакой необходимости отделять (как выше комментировано) их нету
Ничего подобного выше не комментировано. Без отделения переменных нет никакого способа визуально отличить объявление переменной от объявлений свойств элемента. Способ выделения — дело вкуса и привычки, это уже вопрос чисто субъективный.
msts2017
04.07.2017 14:11+1Я про этот комментарий.
Нет необходимости визуально отличать переменные от свойств, свойства это просто предефайненные переменные.msts2017
04.07.2017 14:20да даже так — var-ссссс-ссссс (допустим «var-» обязательно), выглядит более уместно:
.title { var-title-width: 300px; width: calc(var-title-width + 150px); }
CodeViking
04.07.2017 14:47Я не пониманию в чём проблема понять, что для объявления и использования переменной, необходимо писать -- перед именем. Если вы этого делать не будете, то браузер будет парсить имя переменной как неопределенное свойство CSS.
Авторы технологии приняли решение о таком синтаксисе, и с этим ничего не поделаешь.
PHmaster
06.07.2017 03:05Хорошо, если свойства вам хочется назвать "предефайненными переменными", то это нововведение правильней было бы назвать "юзер-дефайнед константами". В языке С, например, константы принято именовать заглавными буквами (хотя это не строгое требование компилятора, а просто выработанный многолетним опытом программистов code style). Так просто кодить реально удобнее, когда мух от котлет визуально легко отличить, особенно когда у нас килограмм мух в центнере котлет размешан.
P.S. Ну и для совместимостями с будущими версиями — если вдруг у какого-то элемента появится новое свойство в следующей версии HTML/CSS — у программистов, дизайнеров и верстальщиков не будет головной боли по поводу "а не назвали ли мы так наши переменные в нашем коде, и не нужно ли теперь в срочном порядке их везде переименовывать".
enabokov
06.07.2017 01:54Edge вполне себе современный браузер. Пользуюсь им на корпоративном лэптопе, даже удивляюсь. IE находится в замороженном состоянии, как мне видится. Если и будет обновляться, то раз в n лет (как обычно).
anttoshka
04.07.2017 13:53А где можно увидеть реальное применение этих переменных, так чтобы это выглядело удобным? Я пока что для себя не могу придумать. И есть ли полифилы?
anmiles
04.07.2017 15:30Константа, от которой вы пляшете. Например, ширина рабочей области и отступ, согласованный с дизайнером. Цвета. Список семейств шрифтов. Потом в CSS это просто используется. При необходимости меняется в единственном месте. И самое главное: все зависимости от константы прописаны явно. Вам не нужно вспоминать, почему где-то тот или иной меджик намбер, более того — вообще от них избавиться.
anttoshka
04.07.2017 16:26При разработке вопросов не возникает, но эту нишу закрывают сейчас препроцессоры, которые все равно удобнее использовать чем нативный CSS. Наверное вопрос нужно немного перефразировать. Какое применение переменных при работе сайта (не разработке)?
AlexKeller
06.07.2017 23:00Очень важное отличие переменных препроцессоров и чистого CSS, что в препроцессорах переменные неизменны, а в CSS могут меняться внутри селекторов. К тому же, удобно использовать их в media queries
Вот небольшая статья об этом
bro-dev
04.07.2017 14:54Переменные давно уже существуют в препроцесорах, для себя так и не нашёл их применения, поиск и замена по файлам быстрее и проще.
AlexKeller
04.07.2017 16:43Это лучшее решение, которое я только видел!
tasty_brains
05.07.2017 05:38Это же сарказм, да?
AlexKeller
05.07.2017 09:39+1Ну как можно )) это ж так увлекательно, берешь какое-нибудь магическое 12 и ищешь, и ищешь! А потом приходит такооое удовлетворение от качественно выполненной работы, сам собой гордиться начинаешь!
dom1n1k
10.07.2017 04:01Я тоже так подумал поначалу, но это принципиальная ошибка.
Нативные переменные намного круче и гибче, потому что их можно менять налету, а препроцессорные существуют только на этапе компиляции.
FSA
04.07.2017 21:22Ну тут история как с IE6. Чтобы в продакшене верстать, то надо будет добавлять все костыли пока оно не умрёт. Сейчас разве что жать когда IE умрёт окончательно…
hosembafer
05.07.2017 12:56Надо было и про полифил написать и насколько он накрывает базовый функционал.
CodeViking
05.07.2017 13:18Наверное можно было бы пару слов сказать о них (если получится уместить материал в «пару слов»), но это одна из сотни возможностей, сделать стили гибче и лучше. Не каждый будет внедрять post-css в свой огромный проект, или изощряться с транспайлерами, дабы иметь наконец возможность писать эти переменные. Во вторых, я не могу быть уверен, что технологию можно заполифилить целиком. И в третьих, статья преследует цель познакомить читателя с технологией, всё.
dkameleon
06.07.2017 08:32+1боюсь предположить, что будут означать три минуса перед словом в следующей спецификации...
izzholtik
Зачем дефисы перед именем переменной?
CodeViking
Такое правило спецификации. Нужно же как-то отделить кастомное свойство от остальных.
AngReload
Из-за такого синтаксиса переменных печатать их неудобно, а код выглядит неаккуратно.
baldrs
Да, интересно, чем им $var_name как в SCSS не угодил
ivan386
Может чтоб не мешать CSS с SCSS?
Aingis
Помните браузерные префиксы? Вроде
-webkit-linear-gradient
? Так тут то же самое, только с пустым именем префикса, как-webkit-
без слова «webkit
»:--
имя-переменной^
тут ничего
Обсуждались разные варианты: Начало с доллара «$» слишком похоже на Перл и конфликтует с препроцессорами. «var-» плохо выглядит с функцией
var()
: «var(var-
имя-переменной)
».Так что, это самый понятный и не конфликтующий с другими свойствами вариант.
Dimensi
Автор спецификации объяснил это тем, что переменные это то, что внес сам разработчик, и типо они не от браузера или спецификации. Когда браузер вносит свое свойство, которое еще типо не доработано или еще по каким то причинам, то начинает его с -webkit-, а в случае с переменные это, то что внес разраб и поэтому нету имени, между — -.
Я когда читал это, не думал, что придется кому-то объяснять. Поэтому, не обратил на это должного внимания)