Программирование

Подводные камни пользовательских CSS-свойств

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

Обучение в онлайн-университете: курс «Старт в программировании»

Правила синтаксиса названий пользовательских свойств

Мы привыкли, что встроенные CSS-свойства нечувствительны к регистру. Поэтому следующие способы объявления свойства border дадут одинаковый результат:

button {
 BORDER: 2px solid #800080;
}

button {
 border: 2px solid #800080;
}

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

button {
 —NETOLOGY-BRAND-COLOR: #800080;
 —netology-brand-color: #27ae60;
   
 border: 2px solid var(—NETOLOGY-BRAND-COLOR);
 color: var(—netology-brand-color);  
}

Теперь рамка стала цветом #800080 (фиолетовый), а цвет текста — #27ae60 (зеленый).

Допустимые значения для пользовательских свойств

У обычного CSS-свойства можно задать только разрешенные по стандарту значения. Согласно стандарту пользовательских свойств, в качестве значения можно использовать любое существующее корректное CSS-значение. Например, как у всех следующих пользовательских свойств:

.element::before {
 —color: rgba(0, 0, 0, 1);
 —hex: #000000;
 —value: 20px;
 —number: 3;
 —text: "Hey, what's up?";
 —keyword: currentColor;
}

Для примера зададим рамку с цветом #800080 для кнопки:

button {
 —netologyBrandColor: #800080;
 border-width: 2px;
 border-style: solid;
 border-color: var(—netologyBrandColor);
}

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

button {
 —netologyBrandColor: #800080;
 —buttonBorderColor: var(—netologyBrandColor);
 border-width: 2px;
 border-style: solid;
 border-color: var(—buttonBorderColor);
}

Результат ничем отличается от предыдущего, и у кнопки все так же рамка с цветом #800080.

Если у пользовательского свойства —netologyBrandColor будет некорректное значение для свойства border-color, например 18px, то рамка станет черной.  

button {
 —netologyBrandColor: 18px;  
 —buttonBorderColor: var(—netologyBrandColor);
 border-width: 2px;
 border-style: solid;
 border-color: var(—buttonBorderColor);
}

Дело в том, что прежде чем браузер применит значение пользовательского свойства для встроенного свойства, он проверит его на корректность. Если значение доступно для встроенного свойства, то браузер применит его. А если нет, то установит для встроенного свойства значение по умолчанию.

В нашем случае 18px некорректное значение для встроенного свойства border-color, и поэтому браузер установит значение по умолчанию, т.е currentColor. Это очень легко проверить, задав для свойства color значение #800080:

button {
 —netologyBrandColor: 18px;  
 —buttonBorderColor: var(—netologyBrandColor);
 border-width: 2px;
 border-style: solid;
 border-color: var(—buttonBorderColor);
 color: #800080;
}

Как видим, браузер применил значение #800080 для рамки. В этом примере я использовал полный синтаксис, чтобы установить рамку. Но мы можем использовать краткий, а именно свойство border.

button {
 —netologyBrandColor: 18px;  
 —buttonBorderColor: var(—netologyBrandColor);
 border: 2px solid var(—buttonBorderColor);
 color: #800080;
}

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

В нашем примере у встроенного свойства border в качестве одного из значений установлено пользовательское свойство —buttonBorderColor с некорректным значением 18px. Согласно описанному алгоритму, браузер просто проигнорировал свойство border, поэтому у элемента пропала рамка.

Значение по умолчанию для пользовательских свойств

Когда мы рассматривали пример с функцией var, то использовали только один параметр — название пользовательского свойства.

button {
 —netologyBrandColor: #800080;
 border: 2px solid var(—netologyBrandColor);
 color: var(—netologyBrandColor);
}

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

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

Когда браузер поймет, что разработчик не объявил значение для пользовательского свойства, то использует значение по умолчанию. Например значение #800080 (фиолетовый) для пользовательского свойства —netologyBrandColor.

button {
 border: 2px solid var(—netologyBrandColor, #800080);
 color: var(—netologyBrandColor, #800080);
}

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

Мы видим, что рамка и текст стали фиолетовыми. Но если навести на кнопку, то они станут зелеными. Это говорит о том, что браузер применил значение #27ae60 для пользовательского свойства, тем самым заменив значение по умолчанию.

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

Но можно сделать по-другому. Функция var позволяет передавать другую функцию var, поэтому в качестве значения по умолчанию можно задать другое пользовательское свойство. Я перепишу предыдущий пример с использованием пользовательского свойства —defaultButtonColor:

button {
 —defaultButtonColor: #800080;
 
 border: 2px solid var(—netologyBrandColor, var(—defaultButtonColor));
 color: var(—netologyBrandColor, var(—defaultButtonColor));
}

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

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

Наследование пользовательских свойств

В CSS работает механизм наследования, который позволяет элементам наследовать свойства у родительских элементов. В этом плане пользовательские свойства ничем не отличаются от них. Для примера я напишу код, в котором пользовательское свойство —netologyBrandColor наследуется от родительского элемента body.

body {
 —netologyBrandColor: #800080;
}

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

Посмотрев в инспектор, можно заметить надпись “Inherited from body”, которая показывает нам, что пользовательское свойство было взято из элемента body. Но если для элемента button добавить пользовательское свойство —netologyBrandColor, то оно уже перекроет свойство из элемента body.

body {
 —netologyBrandColor: #800080;
}

button {
 —netologyBrandColor: #27ae60;
 border: 2px solid var(—netologyBrandColor);
 color: var(—netologyBrandColor);
}

В инспекторе видно, что пользовательское свойство —netologyBrandColor у элемента button переопределило свойство —netologyBrandColor, которое мы указали для элемента body.

Глобальные значения

В стандарте CSS Custom Properties ввели особенный псевдокласс root, который позволяет указать пользовательские свойства, которые применяются к корневому элементу документа. Например, в HTML-документе к элементу html.

:root {
 —netologyBrandColor: #800080;
}

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

В инспекторе мы можем увидеть, что объявленное пользовательское свойство применяется к элементу html. Но, кроме HTML-документа, псевдокласс root  работает в SVG-документах. Например, я объявлю пользовательские свойства в теге style.

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 28" width="50" height="50">
   <style>
       :root{
           —iconColor: #ffcc00;
           —iconStroke: #000000;
           —iconStrokeWidth: 2px;
       }
   </style>
   <path stroke="var(—iconStroke)"
         stroke-width="var(—iconStrokeWidth)"
         fill="var(—iconColor)"
         d="M26 10.109c0 .281-.203.547-.406.75l-5.672 5.531 1.344 7.812c.016.109.016.203.016.313 0 .406-.187.781-.641.781a1.27 1.27 0 0 1-.625-.187L13 21.422l-7.016 3.687c-.203.109-.406.187-.625.187-.453 0-.656-.375-.656-.781 0-.109.016-.203.031-.313l1.344-7.812L.39 10.859c-.187-.203-.391-.469-.391-.75 0-.469.484-.656.875-.719l7.844-1.141 3.516-7.109c.141-.297.406-.641.766-.641s.625.344.766.641l3.516 7.109 7.844 1.141c.375.063.875.25.875.719z"/>
</svg>

 

И здесь мы видим, что у корневого элемента SVG добавился псевдокласс root. Соответственно, это доказывает, что псевдокласс root применяется не только к тегу html, а к любому корневому элементу.

Заключение

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

Читать еще: «Введение в пользовательские CSS-свойства»

Мнение автора и редакции может не совпадать. Хотите написать колонку для «Нетологии»? Читайте наши условия публикации. Чтобы быть в курсе всех новостей и читать новые статьи, присоединяйтесь к Телеграм-каналу Нетологии.