Автор курса «HTML-верстка» Стас Мельников рассказал, что такое пользовательские CSS-свойства и почему их стоит изучить. 

Стандарт CSS Custom Properties изменил CSS. Появились безумные возможности, о которых раньше мы могли только мечтать. Рассказываем, какие именно и почему новичкам стоит изучить их как можно быстрее. 

Что такое пользовательское свойство


Пользовательское свойство — это CSS-свойство, которое создал сам разработчик. Браузер ничего не знает о таком свойстве, пока его не объявили.
Объявление пользовательского свойства начинается с двойного дефиса, после которого указывают название, ставят двоеточие и добавляют значение.

Для примера объявим пользовательское свойство --netologyBrandColor со значением purple для элемента button:

button {
  --netologyBrandColor: purple;
}

Теперь браузер знает о нашем свойстве, но в чем его польза?

Особенности пользовательских свойств


Первая фишка — функция var. С помощью этой функции мы можем сказать браузеру, чтобы он взял значение из объявленного пользовательского свойства и добавил его для встроенного свойства.

Чтобы браузер так сделал, разработчику нужно объявить встроенное свойство, например, color, и добавить к нему в качестве значения функцию var, в аргументе которой передать название пользовательского свойства.

Для примера добавим пользовательское свойство для встроенных свойств border и color:

button {
  --netologyBrandColor: purple;
  border: 2px solid var(--netologyBrandColor);
  color: var(--netologyBrandColor);
}

В браузере кнопка будет выглядеть так:



Зачем изучать пользовательские свойства, если есть переменные в Sass и они полностью устраивают?

Переменные в препроцессорах, таких как LESS и Sass, помогают организовать код, чтобы нам было проще поддерживать его. Например, в следующем коде я использую переменную $netologyBrandColor, в которой хранится основной цвет бренда:

$netologyBrandColor: purple;

button {
  border: 2px solid $netologyBrandColor;
  color: $netologyBrandColor;
}

После преобразования кода в браузере мы увидим следующий код:

button {
  border: 2px solid purple;
  color: purple;
}

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

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

button {
  --netologyBrandColor: purple;
  border: 2px solid var(--netologyBrandColor);
  color: var(--netologyBrandColor);
}

button:hover {
  --netologyBrandColor: #27ae60;
}



Теперь, если у кнопки сработает состояние hover, значения у свойств border и color изменятся. Именно из-за этой особенности пользовательские свойства и называют «живыми»: они могут изменяться прямо в браузере, и соответственно менять значения встроенных свойств, к которым они применяются.  

В качестве еще одного примера изменю значение пользовательского свойства при состоянии focus.

button {
  --netologyBrandColor: #000000;

  border: 2px solid var(--netologyBrandColor);
  color: var(--netologyBrandColor);
}

button:hover {
  --netologyBrandColor: #27ae60;
}

button:focus {
  --netologyBrandColor: #c0392b;  
  outline: 3px solid var(--netologyBrandColor);
}



Способность динамического изменения пользовательских свойства можно сочетать с Sass-переменными или LESS-переменными.

Пользовательские свойства и media-выражения


Еще одна возможность пользовательских свойств — их значения можно переключать с помощью медиазапросов.

Для примера создадим два пользовательских свойства: —mq и —textColor. При помощи первого выведем название медиафункции на страницу, а второе нужно для переключения цвета. На экранах с шириной до 768px текст будет пурпурным, а от 769px — красным.

body::before {
  content: var(--mq);
  color: var(--textColor);
}

@media (max-width: 768px) { 
  body::before {
    --mq: "max-width: 768px";
    --textColor: purple;
  }
}

@media (min-width: 769px) {
  body::before {
    --mq: "min-width: 769px";
    --textColor: red;
  }
}





Пользовательские свойства и функция calc


В CSS есть функция calc, с помощью которой можно выполнять арифметические операции. Она также может работать и с пользовательскими свойствами. Например, мы можем контролировать количество дочерних элементов в ряду:

.child {
  width: calc(100% / var(--childCount));
}

Если добавить значение 5 для пользовательского свойства --childCount в браузере, увидим следующую картину:



Для разнообразия изменю 5 на 7 и элементы перестроятся.  



Пользовательские свойства и SVG


Еще одна возможность пользовательских свойств — с их помощью можно задать значение для таких SVG-свойств, как fill, stroke, stroke-width и других. Это можно сделать двумя способами.

В первом способе будем использовать атрибуты fill, stroke и stroke-width, к которым в качестве значения определим пользовательские свойства.

<svg class="svg-with-attr" viewBox="0 0 26 28">
  <path stroke="var(--iconStroke)" stroke-width="var(--iconStrokeWidth)" fill="var(--iconFill)" d="...">
</svg>

И добавим в CSS значения для пользовательских свойств:

.svg-with-attr{
  --iconFill: #eeeeee;
  --iconStroke: #000000;
  --iconStrokeWidth: 1px;
}



Слева иконка без стилизации, а справа с нашими настройками. Вот так просто мы можем настраивать графику.

Второй способ — убрать атрибуты их и заменить на CSS-свойства.

<svg class="svg-with-props" viewBox="0 0 26 28">
  <path d="...">
</svg>

.svg-with-props {
  --iconFill: #ffcc00;
  --iconStroke: #000000;
  --iconStrokeWidth: 2px;

  stroke: var(--iconStroke);
  stroke-width: var(--iconStrokeWidth);
  fill: var(--iconFill);
}



Я специально добавил для свойств fill, stroke и stroke-width другие значение, чтобы визуально была заметна разница между примерами.

Поддержка браузерами


Согласно caniuse.com, пользовательские свойства работают в большинстве современных браузеров, кроме IE11.



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

Если же вам не нужно поддерживать IE11, смело используйте все возможности пользовательских свойств.

Заключение


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

От редакции


Курсы «Нетологии» по теме:

Комментарии (19)


  1. DarkPreacher
    30.11.2018 13:22

    Использовал пользовательские свойства в стиле для Stylish, переоформлял 4pda в тёмные цвета и несколько личных проектов. Смысл был в том, чтобы разделить стили на два файла — в одном задаётся оформление для конкретного сайта, во второй вынесены цвета для формата HSL и применяется он для всех сайтов, таким образом правя цвета в одном файле — я могу изменить оформление сразу для нескольких сайтов. И у пользователей не возникает проблем с обновлением базового стиля, потому как править его нет причин.


  1. agentx001
    30.11.2018 15:27
    +1

    CamelCase в CSS — вы серьёзно? :)


    1. Klenov_s
      30.11.2018 17:24

      У вас есть сведения, что от этого браузер работает хуже? )


      1. agentx001
        01.12.2018 18:40

        Есть общепринятые правила и мне кажется их следует придерживаться при написании кода для широкой публики.
        У меня тоже есть свои JS извращения: двойные кавычки, отступ из четырех пробелов. Но приходиться сдерживаться :)


        1. Klenov_s
          01.12.2018 19:48

          Если отказаться от привычки выдавать свои пристрастия за правила, то жизнь становится немного проще )


        1. ElianL
          01.12.2018 20:05

          нет общепринятых правил. Есть правила принятные на конктретном проекте, не более. Плюс подходы типа CSSModlues лучше работают именно с camelCase нотацией


          1. agentx001
            01.12.2018 20:57

            Разве не кажется по крайней мере логичным использовать стилизацию близкую к нативной?
            А насчет общепринятости — у стайл гайдов airbnb на гитхабе в сумме почти 100к звездочек. И это я не говорю про практически идентичные гайды гугла. Имхо этого достаточно что бы считать эти правила общепринятыми.


      1. barkalov
        03.12.2018 05:33

        А что, это единственный критерий? Сочувствую вашим коллегам.


  1. Intrinit
    30.11.2018 18:37

    я правильно понимаю, что переменную надо заводить специально для определенного селектора? в чем смысл, кроме дублирования кода?
    тут либо примеры не удачные, либо сам функционал еще не доведен до объективно-полезного.


    1. melnik909
      01.12.2018 21:02

      Нет. Пользовательские свойства могут также наследоваться. В следующей статье об этом и будет рассказано. И примеры подобраны с целью показать, что можно сделать теоретически. Практические примеры будут в другой статье.


  1. PaulZi
    30.11.2018 20:25

    Главное преимущество пользовательских свойств, в том что они наследуются и переопределяется в Dom. Это гораздо круче переменных в препроцессора.


  1. b360124
    01.12.2018 22:28

    Если на вашем проекте много пользователей с IE11, не применяйте пользовательские свойства. Я мог бы рассказать, как сделать фоллбэки...

    А с этого места поподробнее? А то я заюзал как-то полиффил но как-то криво он работал


    1. melnik909
      01.12.2018 09:58
      -1

      Можно:
      — использовать supports или отдельную версию для IE 11, но тогда раздувается код
      — можно использовать PostCSS плагины, и довольствоваться ограниченными возможностями

      Поэтому если есть IE11 или другие браузеры, которые не поддерживают пользовательские свойства, то лучше отложить свое желание для другого проекта


    1. AngReload
      01.12.2018 10:22

      Фоллбэки это не полифиллы, а дублированные свойства без использования переменных:


      .main {
        color: #212121;
        background: #fafafa;
        color: var(--main-color);
        background: var(--main-bg);
      }

      Ну и у полифиллов есть ограничения, для работы css-vars-ponyfill пользовательские свойства должны быть только в root:


      :root {
        --a: var(--b);
        --b: var(--c);
        --c: 10px;
      }
      
      div {
        padding: calc(2 * var(--a));
      }


      1. b360124
        01.12.2018 23:09

        Спасибо, в css-vars-ponyfill то что свойства должны быть в :root меня и смутило когда я его тестил, это практически весь цымес от кастомных переменных и теряется, когда нужно в зависимости от элемента дом задать определенные значения правилам. Видимо для IE11 нет и не будет полноценного полифилла.


  1. Extremum
    01.12.2018 01:13

    Вообще интересное нововведение, но преимуществ перед Sass не вижу, задавать значения переменных в коде == сойти с ума в правках на больших проектах. Все что указали — переменной Sass нет в браузере, а какой выигрыш если бы была?


    1. Reey
      01.12.2018 05:41

      Преимущество перед sass в том, что переменные

      — следуют структуре dom:

      Простой пример: сейчас можно делать сайты где можно переключать дневную/ночную тему. В принципе в sass это решается, но с переменными становится вообще просто.

      пример на sass
      a {
      	color: blue;
      }
      
      .content {
      	background: white;
      	color: black;
      }
      
      /* далее фактически идет дифф оригинального цсс */
      html[data-theme="night"]{
      	a {
      		color: red;
      	}
      
      	.content {
      		background: black;
      		color: white;
      	}
      }
      


    1. melnik909
      01.12.2018 09:56
      -1

      Преимущества пользовательских свойств:
      — можно менять значение в медиа-запросах (пример в статье с переключением цвета и текста)
      — без костылей работает calc (я помню был баг либо в Less, либо в Sass)
      — работают с атрибутами (пример в статье с svg)
      — меньше писать кода для состояний hover, focus и т.п

      И сравнение пользовательских свойств с Sass переменным некорректно. Они могут спокойно существовать вместе


    1. ElianL
      01.12.2018 20:12

      К примеру вот такого на препроцессорах не сделаешь.

      .icon {
        --size: 18px;
        
        width: var(--size);
        height: var(--size);
      
        @media (max-width: 400px) {
           --size: 16px;
        }
      
      }
      


      Плюс не забыаем, что css в браузере отлично управляется через js. А значит мы можем меня ть значения каких-либо css переменных в рантайме