Всем привет, тема переменных в 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 будет меняться цвет фона у элемента. Круто? Ещё бы! Не нужно добавлять новый класс, переопределять свойство или делать другие действия, способствующие изменению фонового цвета у элемента.

Ремарка
Если кто-то не знаком с React или кому-то просто непонятно, что произошло. Мы просто средствами JavaScript изменили аттрибут style у элемента, изменив значение переменной
--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)


  1. izzholtik
    04.07.2017 11:39

    Зачем дефисы перед именем переменной?


    1. CodeViking
      04.07.2017 11:40

      Такое правило спецификации. Нужно же как-то отделить кастомное свойство от остальных.


      1. AngReload
        04.07.2017 12:27

        Из-за такого синтаксиса переменных печатать их неудобно, а код выглядит неаккуратно.


        1. baldrs
          04.07.2017 20:08
          +1

          Да, интересно, чем им $var_name как в SCSS не угодил


          1. ivan386
            04.07.2017 21:07
            +2

            Может чтоб не мешать CSS с SCSS?


    1. Aingis
      05.07.2017 18:09

      Помните браузерные префиксы? Вроде -webkit-linear-gradient? Так тут то же самое, только с пустым именем префикса, как -webkit- без слова «webkit»:
      --имя-переменной
       ^
      тут ничего


      Обсуждались разные варианты: Начало с доллара «$» слишком похоже на Перл и конфликтует с препроцессорами. «var-» плохо выглядит с функцией var(): «var(var-имя-переменной)».


      Так что, это самый понятный и не конфликтующий с другими свойствами вариант.


    1. Dimensi
      06.07.2017 14:15
      +1

      Автор спецификации объяснил это тем, что переменные это то, что внес сам разработчик, и типо они не от браузера или спецификации. Когда браузер вносит свое свойство, которое еще типо не доработано или еще по каким то причинам, то начинает его с -webkit-, а в случае с переменные это, то что внес разраб и поэтому нету имени, между — -.
      Я когда читал это, не думал, что придется кому-то объяснять. Поэтому, не обратил на это должного внимания)


  1. almassar
    04.07.2017 11:39
    +3

    У меня в голове ну укладывается, почему такая мощная организация как Microsoft, не может сделать нормальный современный браузер?.. Тем более что многие стандарты по CSS разрабатывали их сотрудники.


    1. msts2017
      04.07.2017 13:21

      У меня в голове не укладывается как вообще кому-то пришло в голову имя переменной начинать с дефисов, ведь никакой необходимости отделять (как выше комментировано) их нету, наоборот весь стиль это набор переменных, на месте Microsoft из принципа такое говно не пропустил.


      1. PHmaster
        04.07.2017 13:58

        никакой необходимости отделять (как выше комментировано) их нету

        Ничего подобного выше не комментировано. Без отделения переменных нет никакого способа визуально отличить объявление переменной от объявлений свойств элемента. Способ выделения — дело вкуса и привычки, это уже вопрос чисто субъективный.


        1. msts2017
          04.07.2017 14:11
          +1

          Я про этот комментарий.
          Нет необходимости визуально отличать переменные от свойств, свойства это просто предефайненные переменные.


          1. msts2017
            04.07.2017 14:20

            да даже так — var-ссссс-ссссс (допустим «var-» обязательно), выглядит более уместно:

            .title {
              var-title-width: 300px;
              width: calc(var-title-width + 150px);
            }
            


            1. CodeViking
              04.07.2017 14:47

              Я не пониманию в чём проблема понять, что для объявления и использования переменной, необходимо писать -- перед именем. Если вы этого делать не будете, то браузер будет парсить имя переменной как неопределенное свойство CSS.

              Авторы технологии приняли решение о таком синтаксисе, и с этим ничего не поделаешь.


          1. PHmaster
            06.07.2017 03:05

            Хорошо, если свойства вам хочется назвать "предефайненными переменными", то это нововведение правильней было бы назвать "юзер-дефайнед константами". В языке С, например, константы принято именовать заглавными буквами (хотя это не строгое требование компилятора, а просто выработанный многолетним опытом программистов code style). Так просто кодить реально удобнее, когда мух от котлет визуально легко отличить, особенно когда у нас килограмм мух в центнере котлет размешан.


            P.S. Ну и для совместимостями с будущими версиями — если вдруг у какого-то элемента появится новое свойство в следующей версии HTML/CSS — у программистов, дизайнеров и верстальщиков не будет головной боли по поводу "а не назвали ли мы так наши переменные в нашем коде, и не нужно ли теперь в срочном порядке их везде переименовывать".


    1. enabokov
      06.07.2017 01:54

      Edge вполне себе современный браузер. Пользуюсь им на корпоративном лэптопе, даже удивляюсь. IE находится в замороженном состоянии, как мне видится. Если и будет обновляться, то раз в n лет (как обычно).


  1. Kozack
    04.07.2017 11:56
    +3

    Если послать нахрен ишака, то вполне можно применять.


    1. Vadem
      05.07.2017 13:54
      +1

      Даже с ишаком можно применять, если использовать, например, cssnext.


      1. Dartess
        10.07.2017 14:55

        cssnext просто скомпилирует результат, с ним нельзя будет работать из js, например. Кастомные свойства это не просто про переменные препроцессоров.


  1. anttoshka
    04.07.2017 13:53

    А где можно увидеть реальное применение этих переменных, так чтобы это выглядело удобным? Я пока что для себя не могу придумать. И есть ли полифилы?


    1. anmiles
      04.07.2017 15:30

      Константа, от которой вы пляшете. Например, ширина рабочей области и отступ, согласованный с дизайнером. Цвета. Список семейств шрифтов. Потом в CSS это просто используется. При необходимости меняется в единственном месте. И самое главное: все зависимости от константы прописаны явно. Вам не нужно вспоминать, почему где-то тот или иной меджик намбер, более того — вообще от них избавиться.


      1. anttoshka
        04.07.2017 16:26

        При разработке вопросов не возникает, но эту нишу закрывают сейчас препроцессоры, которые все равно удобнее использовать чем нативный CSS. Наверное вопрос нужно немного перефразировать. Какое применение переменных при работе сайта (не разработке)?


        1. AlexKeller
          06.07.2017 23:00

          Очень важное отличие переменных препроцессоров и чистого CSS, что в препроцессорах переменные неизменны, а в CSS могут меняться внутри селекторов. К тому же, удобно использовать их в media queries

          Вот небольшая статья об этом


  1. bro-dev
    04.07.2017 14:54

    Переменные давно уже существуют в препроцесорах, для себя так и не нашёл их применения, поиск и замена по файлам быстрее и проще.


    1. AlexKeller
      04.07.2017 16:43

      Это лучшее решение, которое я только видел!


      1. tasty_brains
        05.07.2017 05:38

        Это же сарказм, да?


        1. AlexKeller
          05.07.2017 09:39
          +1

          Ну как можно )) это ж так увлекательно, берешь какое-нибудь магическое 12 и ищешь, и ищешь! А потом приходит такооое удовлетворение от качественно выполненной работы, сам собой гордиться начинаешь!


    1. dom1n1k
      10.07.2017 04:01

      Я тоже так подумал поначалу, но это принципиальная ошибка.
      Нативные переменные намного круче и гибче, потому что их можно менять налету, а препроцессорные существуют только на этапе компиляции.


  1. Eldhenn
    04.07.2017 15:20
    +1

    > Приведу грубый пример на React

    А без реакта?


    1. xoposhiy
      05.07.2017 06:38

      Реакт — это новый jQuery. Без него никак! ;)


  1. FSA
    04.07.2017 21:22

    Ну тут история как с IE6. Чтобы в продакшене верстать, то надо будет добавлять все костыли пока оно не умрёт. Сейчас разве что жать когда IE умрёт окончательно…


  1. LamerX
    05.07.2017 05:38

    Хм… Довольно неплохая штучка))


  1. hosembafer
    05.07.2017 12:56

    Надо было и про полифил написать и насколько он накрывает базовый функционал.


    1. CodeViking
      05.07.2017 13:18

      Наверное можно было бы пару слов сказать о них (если получится уместить материал в «пару слов»), но это одна из сотни возможностей, сделать стили гибче и лучше. Не каждый будет внедрять post-css в свой огромный проект, или изощряться с транспайлерами, дабы иметь наконец возможность писать эти переменные. Во вторых, я не могу быть уверен, что технологию можно заполифилить целиком. И в третьих, статья преследует цель познакомить читателя с технологией, всё.


  1. dkameleon
    06.07.2017 08:32
    +1

    боюсь предположить, что будут означать три минуса перед словом в следующей спецификации...