Что можно поместить в CSS-переменную

Css
article image

В этом посте обсудим, что можно поместить в CSS-переменную.

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

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

Единицы измерения и немного математики.

Начнем с простого. Обычно в переменные помещают всякие единицы измерения или, проще говоря, размеры.

1
2
3
4
5
6
7
8
9
:root {
  --nice-padding: 20px;
  --nice-font-size: 1.25rem;
}
  
article {
  padding: var(--nice-padding);
  font-size: var(--nice-font-size);
}

Так же переменные могут содержать результаты математических вычислений, полученные при помощи calc(), с использованием других переменных.

1
2
3
4
5
6
7
8
9
10
11
:root {
  --image-width: 800px;

  /* расчитываем высоту с сохраниением пропорции 4:3 */
  --image-height: calc(var(--image-width) / (4/3));
}
    
img {
  width: var(--image-width);
  height: var(--image-height);
}

Похожим образом переменные можно использовать со встроеннымы функциями CSS.

1
2
3
4
5
6
7
8
9
:root {
  --min: 1rem;
  --max: 4rem;
  --clamped-font-size: clamp(var(--min), 2.5vw, var(--max));
}
  
p {
  font-size: var(--clamped-font-size);
}

Переменные без единиц измерения.

Переменные могут содержать значения без конкретных единиц измерения.

1
2
3
4
5
6
7
:root {
  --obnoxiously-big-number: 9001;
}
    
.important-modal {
  z-index: var(--obnoxiously-big-number);
}

Но в любом случае вы позже сможете добавить нужную единицу измерения просто умножив значение на 1px/%/rem при помощи все той же calc().

1
2
3
4
5
6
7
8
9
:root {
  --magic-number: 41;
}
    
.crazy-box {
  width: calc(var(--magic-number) * 1%); /* результат будет в процентах */
  padding: calc(var(--magic-number) * 1px); /* в пикселях */
  transform: rotate(calc(var(--magic-number) * 1deg)); /* в градусах */
}

Нечисловые значения

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

1
2
3
4
5
6
7
8
9
:root {
  --bullets: circle;
  --casing: uppercase;
}
    
ul {
  list-style-type: var(--bullets);
  text-transform: var(--casing);
}

В переменнной так же могут быть и пользовательские идетификаторы, которые вы определяете сами, например для animation-name или grid-area.

1
2
3
4
5
6
7
8
9
10
11
:root {
  --layout-position: center-stage;
}
    
body {
  grid-template-areas: 'left center-stage right';
}
    
main {
  grid-area: var(--layout-position);
}

Строчные значения

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

Следущее свойсво content покажет содержимое, сформированное строковыми переменными. А так же вы увидите как можно объединять переменные и обычные строки и как извлечь значение из атрибута с помощью attr().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
:root {
  --open: '(';
  --close: ')';
  --heading-hint: ' ' var(--open) 'this is a heading' var(--close);
  --link-hint: ' ' var(--open) attr(href) var(--close);
}
  
h1::after {
  content: var(--heading-hint);
}
  
a::after {
  content: var(--link-hint);
}

Демо:

See the Pen CSS Variables with Content Strings by Will Boyd (@lonekorean) on CodePen.

Изображения

CSS-переменные так же могут содежрать изображения. Они могут быть отображены с помощью свойства content, но привычнее их все же видеть в качестве фона.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
:root {
  /* png изображения с внешнего источника. */
  --image-from-somewhere: url(https://codersblock.com/assets/images/logo.png);

  /* svg встроенное как строка */
  --image-embedded: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath d='M8 256c0 136.966 111.033 248 248 248s248-111.034 248-248S392.966 8 256 8 8 119.033 8 256zm248 184V72c101.705 0 184 82.311 184 184 0 101.705-82.311 184-184 184z'%3E%3C/path%3E%3C/svg%3E");
}
  
.a {
  background-image: var(--image-from-somewhere);
}
  
.b::after {
  content: var(--image-embedded);
}

Это позволяет избавиться от громоздких URL-адресов и заменить их короткими записями.

Сокращенные записи

Переменная может использоваться как часть сокращенной записи CSS-свойства или как целое сокращение. В примере ниже оба контейнера будут иметь одинаковые отступы.

1
2
3
4
5
6
7
8
9
10
11
12
:root {
  --top-padding: 60px;
  --all-padding: 60px 20px 40px 10px;
}
    
.container {
  padding: var(--top-padding) 20px 40px 10px;
}
    
.another-container {
  padding: var(--all-padding);
}

Что инетересно, так это то, что в переменную можно записать сегмет сокращенной записи из нескольких значений.

1
2
3
4
5
6
7
:root {
  --weight-and-size: bold 3rem;
}
  
body {
  font: var(--weight-and-size)/1.25 sans-serif;
}

Списки

Некоторые свойства, такие как background или box-shadow могут иметь целые списки свойств. Вы моежете импользовать переменную как отдельный элемент списка, как подсписок или как весь список.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
  быстро вспомним анатомию box-shadow!
  box-shadow: <x-offset> <y-offset> <blur> <spread> <color>;
*/

:root {
  --single-shadow:
    0 0 0 40px #355c7d;
  --multi-shadow:
    0 0 0 60px #f67280,
    0 0 0 80px #6c5b7b;
  --gradient-colors: #f1bbba, #ece5ce, #c5e0dc;
}

.a {
  box-shadow:
    0 0 0 20px #60b99a,
    var(--single-shadow);
}

.b {
  box-shadow:
    var(--multi-shadow);
}

.c {
  box-shadow:
    0 0 0 20px #60b99a,
    var(--single-shadow),
    var(--multi-shadow);
}

body {
  background-image: linear-gradient(45deg, var(--gradient-colors));
}

Демо:

See the Pen CSS Variables with Shadow Lists by Will Boyd (@lonekorean) on CodePen.

Цвета

Не забываем о цветах! CSS-переменные отлично подходят для хранения в них зачений цветов и очень часто можно увидеть, что они используются для создания цветовых схем сайта.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@media (prefers-color-scheme: light) {
  :root {
    --color-text: #233742;
    --color-links: #d80b77;
    --color-bg: white;
  }
}
  
@media (prefers-color-scheme: dark) {
  :root {
    --color-text: white;
    --color-links: #b4cddd;
    --color-bg: #233742;
  }
}
  
body {
  color: var(--color-text);
  background-color: var(--color-bg);
}

a {
  color: var(--color-links);
}

Вы так же можете поместить в переменную отдельное значение цвета и использовать его в rgb()/rgba() или hsl()/hsla(). Пример с rgb():

1
2
3
4
5
6
7
8
9
:root {
  --red: 216;
  --green: 11;
  --blue: 119;
}
  
a {
  color: rgb(var(--red), var(--green), var(--blue));
}

Совмещение всего для анимации

Можем ли мы положить в переменную анимированное значение?

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

Основная проблема в том, что браузер не понимает как анимировать выдуманные вами переменные. Но есть и хорошие новости! Эту проблему можно решить с помощью API свойств и значений. Оно является частью коллекции Houdini. На данный момент поддерживаются браузерами Chrome, Edge и Opera, но в скором времени должны присоединиться и остальные.

Вот как это работает. Для начала объявляем пользовательские свойства.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@property --red {
  syntax: '<integer>';
  inherits: true;
  initial-value: 0;
}
@property --green {
  syntax: '<integer>';
  inherits: true;
  initial-value: 0;
}
@property --blue {
  syntax: '<integer>';
  inherits: true;
  initial-value: 0;
}

Здесь вы говорите браузеру: "Гляди, вот несколько свойств, это числа с начальным значением 0". На что ваш браузер ответит: "О, целые числа! Я знаю как их анимировать." Теперь мы готовы к анимации.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@keyframes red-fade {
  50% { --red: 255; }
}
@keyframes green-fade {
  50% { --green: 255; }
}
@keyframes blue-fade {
  50% { --blue: 255; }
}

:root {
  animation: red-fade 16s, green-fade 14s, blue-fade 12s;
  animation-iteration-count: infinite;
}

В приведенной выше анимации значение каждой переменной меняется от 0 (заданным изначально) до 255 и обратно.

1
2
3
.swatch {
  background-color: rgb(var(--red), var(--green), var(--blue));
}

Далее эти три независимо анимированные переменные объединяются вместе при помощи rgb() и создают плавное изменение фонового цвета. Скажем "Нет!" JavaScript-у.

See the Pen CSS Variables Color Animation by Will Boyd (@lonekorean) on CodePen.

На самом деле в нашем примере много чего происходит. Три переменные (--red, --green, --blue ) анимируют за собой множество элементов. Давайте разберемся.

Во-первых большое поле с фоновым цветом.

Во-вторых индикаторы движущиеся по цветовым полосам вверх и вниз. Они позиционируются путем преобразования значений переменных в отрицательные. Пример с красным цветом:

1
2
3
.red .indicator {
  transform: translateY(calc(var(--red) * -1px));
}

В-третьих числа под цветными полосами. Здесь есть интересный момент. Как говорилии ранее, свойство content может выводить строки, но оно не работает с целочисленными переменными. Однако в CSS имеются счетчики, которые работают с такими переменными и отображают их значения в качестве строки.

1
2
3
4
5
6
7
.red .value::before {
  /* in goes an integer variable */
  counter-reset: color-value var(--red); 

  /* out comes a string-like counter value */
  content: counter(color-value);
}

По сути мы просто используем CSS счетчик чтобы преобразовать число в строку.

В дополнение

Что касается наследования и каскада, пользовательские свойства подчиняются тем же правилам, что и обычные. Таким образом вы так же можете использовать специальные значения, такие, как initial, inherit, unset и revert в CSS-переменных.

Источник: https://codersblock.com/blog/what-can-you-put-in-a-css-variable/