CSS-переменные (их ещё называют «пользовательскими свойствами») поддерживаются веб-браузерами уже почти четыре года. Я пользуюсь ими там, где они могут пригодиться. Это зависит от проекта, над которым я работаю, и от конкретных задач, которые мне приходится решать. Работать с CSS-переменными просто, они способны принести разработчику немалую пользу. Правда, часто фронтенд-программисты применяют CSS-переменные неправильно или не понимают особенностей работы с ними.
![](https://habrastorage.org/r/w1560/webt/am/sd/sl/amsdsl3qgw4_ursgt9kzvseaot4.png)
Я написал эту статью для того чтобы собрать в ней всё, что я знаю о CSS-переменных. В ходе работы над ней я надеялся узнать о них что-то новое и упорядочить то, что мне уже известно. Вы найдёте в этом материале всё, что нужно знать о CSS-переменных. Здесь имеется множество практических примеров и описаний сценариев использования CSS-переменных.
Готовы? Если так — приступим.
CSS-переменные — это значения, которые объявляют в CSS, преследуя две цели. Первая — это многократное использование таких значений. Вторая — это сокращение объёмов CSS-кода. Рассмотрим простой пример.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/5db/fae/ecc/5dbfaeecc34e27af4ffb682d752ad66f.png)
Стилизация элементов страницы
В этом примере CSS-кода значение
Но при использовании CSS-переменных подобные задачи решаются гораздо проще. Давайте поговорим о том, как объявлять CSS-переменные. Перед именем переменной должно идти два дефиса. Объявим переменную в стиле для псевдокласса
По-моему, этот фрагмент кода выглядит гораздо чище, чем предыдущий. Переменная
Правила именования CSS-переменных не особенно сильно отличаются от правил, принятых в различных языках программирования. А именно, правильное имя CSS-переменной может включать в себя алфавитно-цифровые символы, знаки подчёркивания и дефисы. Кроме того, стоит обратить внимание на то, что имена этих переменных чувствительны к регистру.
CSS-переменные имеют одну полезную особенность, которая заключается в том, что область их видимости можно ограничивать. В основе этой идеи лежат те же принципы, которые применяются в различных языках программирования. Например — в JavaScript:
В этом примере переменная
Переменная
Вот схема, разъясняющая эту идею.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/e1b/0a3/1f2/e1b0a31f2f0135e0a40efb157803c861.png)
Область видимости CSS-переменных
Тут показана переменная
Обычно «резервные значения» используются для обеспечения работоспособности сайтов в браузерах, которые не поддерживают некие современные CSS-механизмы. Но здесь речь пойдёт не об этом, а о том, как задавать значения, используемые в том случае, если нужные CSS-переменные оказываются недоступными. Рассмотрим следующий пример:
Обратите внимание на то, что функции
Этот подход к работе с переменными может оказаться полезным в том случае, если значение переменной зависит от некоего действия. Если может случиться так, что в переменной не будет значения, важно предусмотреть использование резервного значения.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/7c5/049/119/7c5049119f4338288b61481e806cf007.png)
Компоненты разных размеров
В дизайн-системах часто имеются, например, кнопки разных размеров. Как правило, речь идёт о трёх вариантах размеров (маленький, обычный, большой). С использованием CSS-переменных можно очень легко описывать такие кнопки и другие подобные элементы.
Меняя значение переменной
HSL (Hue, Saturation, Lightness — тон, насыщенность, светлота) — это цветовая модель, в которой компонент H определяет цвет, а компоненты S и L определяют параметры насыщенности и светлоты цвета.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/d46/6b8/5b1/d466b85b180659315457ceb1cbf10c10.png)
Цвета элементов, задаваемые с использованием HSL
Обратите внимание на то, как я сделал цвет кнопки темнее, уменьшив значение переменной
Если вас интересует тема использования цветов в CSS — вот моя статья об этом.
Если вы работали в какой-нибудь дизайнерской программе, вроде Photoshop, Sketch, Figma или Adobe XD, то вы можете знать об использовании клавиши
В CSS нет стандартного механизма изменения размеров элементов с сохранением пропорций. Но это ограничение можно обойти, воспользовавшись, как несложно догадаться, CSS-переменными.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/b68/582/ff4/b68582ff4723bcd0a0a419db2e291e81.png)
Настройка размеров элемента с помощью CSS-переменных
Предположим, что у нас имеется значок, ширина и высота которого должны быть одинаковыми. Для того чтобы этого добиться, я определил CSS-переменную
В результате оказывается, что этот приём имитирует использование клавиши
CSS-переменные могут оказаться чрезвычайно полезными при проектировании макетов страниц, основанных на CSS Grid. Представьте, что вам нужно сделать так, чтобы Grid-контейнер выводил бы дочерние элементы, основываясь на заранее заданной ширине элементов. Вместо того чтобы создавать класс для каждого варианта представления элементов, что приведёт к необходимости дублирования CSS-кода, эту задачу можно решить, воспользовавшись CSS-переменными.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/1d3/192/ee2/1d3192ee2ba2efe9fb9e4ef3510e4d56.png)
Настройка размеров Grid-элементов с использованием CSS-переменной
Благодаря такому подходу можно создать гибкий Grid-макет, подходящий для использования в различных проектах, который легко поддерживать. Ту же идею можно применить и для настройки свойства
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/7a9/ab0/d15/7a9ab0d152eccf72f2a848eadc33eb0e.png)
Использование переменной --gap для настройки свойства grid-gap
Под «значениями со сложной структурой» я понимаю, например, нечто вроде градиентов. Если в проекте есть градиент или фон, используемые во многих местах этого проекта, то их описания имеет смысл хранить в CSS-переменных.
В подобных ситуациях в переменных можно хранить и отдельные элементы «сложных» значений. Это, например, может быть угол градиента:
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/9bc/72a/ec6/9bc72aec619db7ad2b70d60a3af62e1b.png)
Разные варианты градиента, созданные путём изменения переменной --angle
Как уже было сказано, CSS-переменные могут хранить значения со сложной структурой. Это может оказаться полезным в том случае, если имеется элемент, который, в зависимости от происходящего, может понадобиться размещать в разных местах страницы.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/1d0/2d8/910/1d02d8910827af2e2e89251ba2f74976.png)
Управление позицией элемента с помощью переменной --pos
Сейчас сайты, почти в обязательном порядке, оснащают тёмной и светлой темой. Для решения этой задачи можно воспользоваться CSS-переменными, храня в них сведения о цветах и переключаясь между ними после анализа системных параметров или настроек, выполненных пользователем.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/8fc/a27/03d/8fca2703dab6ef3ab37330d3b3bff0c2.png)
Светлая и тёмная темы
Вот видеодемонстрация вышеозвученной идеи.
В некоторых ситуациях нужно задавать CSS-переменные с использованием JavaScript. Представим, что нам нужно установить значение свойства
Переменная
В этом примере роль значения, используемого по умолчанию, играет
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/c07/535/b68/c07535b68c1681406b9855ea5d1660ef.png)
Управление шириной элемента-контейнера
Элементы-контейнеры, используемые на веб-страницах, могут, в разных ситуациях, иметь разные размеры. Возможно, на одной странице может понадобиться небольшой контейнер, а на другой — контейнер побольше. В подобных случаях CSS-переменные могут с успехом использоваться для управления размерами контейнеров.
Использование CSS-переменных во встроенных стилях может открыть перед фронтенд-разработчиком массу новых возможностей, о которых он раньше и не подозревал. На самом деле, я написал об этом целую статью, но тут я, всё же, расскажу о самых интересных способах использования переменных во встроенных стилях.
Возможно, в продакшне этими методами лучше не пользоваться. Они очень хорошо подходят для прототипирования и для исследования различных дизайнерских идей.
Например, для настройки ширины элемента можно воспользоваться переменной
Вот HTML-код элемента:
Вот стиль, применяемый к этому элементу:
Здесь можно поэкспериментировать с примером к этому разделу.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/11c/2d5/31a/11c2d531a1228117536cf86ca102f9e2.png)
Аватары разных размеров
Ещё один интересный вариант использования CSS-переменных во встроенных стилях представлен созданием элементов разных размеров. Предположим, нам, в разных ситуациях, нужно выводить аватар пользователя различных размеров. При этом мы хотим управлять его размером с использованием единственной CSS-переменной.
Вот разметка:
Вот стили:
Проанализируем эти стили:
Совместное использование CSS-переменных и медиазапросов может принести немалую пользу в деле настройки значений переменных, используемых на всех страницах веб-сайтов. Самый простой пример использования этой техники, который приходит мне в голову, заключается в настройке расстояния между элементами:
В результате свойства любого элемент, в котором используется переменная
CSS-переменные поддерживают наследование. Если в пределах родительского элемента объявлена CSS-переменная, то элементы-потомки наследуют эту переменную. Рассмотрим пример.
Вот HTML-код:
Вот стили:
Элемент
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/f9d/6b5/3d1/f9d6b53d1178adafdca94b31057c6a25.png)
Наследование CSS-переменных
Тут имеется группа кнопок, к которым предъявляются следующие требования:
Вот разметка к этому примеру:
Вот стили:
Обратите внимание на то, как я использовал переменную
Ещё один пример использования механизма наследования CSS-переменных представлен настройкой CSS-анимаций. Этот пример я взял отсюда.
При таком подходе нам не нужно дважды объявлять
Если оказывается, что с CSS-переменной, переданной функции
Здесь в переменную
Вот схема работы браузера.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/b4f/a45/8de/b4fa458defe561b2e8fb8c85e55e9dbc.png)
Схема работы браузера при обнаружении некорректного значения CSS-переменной
То, о чём шла речь выше, с технической точки зрения, называется «недопустимым значением, появляющимся во время вычислений» (Invalid At Computed-Value Time). Ситуация, в которой появляются такие значения, возникает, когда функции
Рассмотрим следующий пример, который я взял из этой статьи:
Если браузер не поддерживает функцию
Вот что говорится об этом в спецификации CSS:
Концепция появления недопустимого значения во время вычислений существует из-за того, что ошибки, связанные с переменными, не проявляются, в отличие от других синтаксических ошибок, на ранних стадиях работы системы. Поэтому оказывается, что когда пользовательский агент обнаружит, что значение переменной некорректно, он уже отбросит, в соответствии с порядком каскадного применения стилей, другие значения.
В результате оказывается, что если нужно применять возможности CSS, не пользующиеся широкой поддержкой браузеров, при реализации которых используются CSS-переменные, нужно применять директиву
Возможно, некоторые ресурсы, используемые на ваших веб-страницах, нужно загружать из внешних источников. В подобных ситуациях можно хранить URL этих ресурсов в CSS-переменных.
Тут может возникнуть вопрос о том, можно ли обрабатывать конструкции вида
Так поступить не получится, так как функция
В CSS-переменных можно хранить несколько значений. Если это — значения, выглядящие так, как они должны выглядеть в том месте, где планируется использовать переменную, то такая конструкция окажется работоспособной. Рассмотрим пример.
![](https://habrastorage.org/r/w1560/getpro/habr/post_images/366/428/ac7/366428ac76b2fdbee88aa96c07e4f0fb.png)
Значение переменной выглядит так, как ожидается
Вот CSS-код:
Здесь имеется функция
Единственный минус такого подхода заключается в том, что цвет, задаваемый функцией
Вот пример использования CSS-переменной для настройки свойства
Здесь показана стилизация двух разделов сайта. Фон одного из них не должен повторяться по осям
Если вы читали спецификацию, посвящённую CSS-переменным, то вы могли столкнуться там с термином «animation-tainted». С его помощью описывают тот факт, что значения CSS-переменных не поддаются плавному изменению в правиле
Вот HTML-код:
Вот стили:
Анимация в этом случае не будет плавной. Переменная примет лишь три значения:
Если нам нужно обеспечить в предыдущем примере плавную анимацию, то делать это надо так, как делалось раньше. То есть — надо заменить переменную на те CSS-свойства элемента, которые нужно анимировать.
→ Вот пример
Хочу отметить, что после публикации этой статьи мне сообщили о том, что анимировать CSS-переменные в
Здесь можно поэкспериментировать с примером применения этой возможности.
Возможно, вы не знаете о том, что CSS-переменные можно использовать в вычислениях. Взглянем на пример, который мы уже рассматривали, говоря об аватарах:
Размеры аватара зависят от значения переменной
При использовании инструментов разработчика различных браузеров можно применять некоторые полезные приёмы, которые упрощают работу с CSS-переменными. Поговорим о них.
Я считаю полезной возможность видеть цвет, описываемый CSS-переменной. Эта возможность доступна в браузерах Chrome и Edge.
![](https://habrastorage.org/r/w780q1/getpro/habr/post_images/e91/dbc/d2c/e91dbcd2c53dee88f5bed196512af93f.jpg)
Просмотр цвета, задаваемого CSS-переменной
Для того чтобы взглянуть на вычисляемое значение CSS-переменной нужно, в зависимости от браузера, навести на переменную указатель мыши или щёлкнуть мышью по специальной кнопке.
![](https://habrastorage.org/r/w780q1/getpro/habr/post_images/bde/a5b/26b/bdea5b26b12bf6cb648c57833bda809c.jpg)
Просмотр вычисляемых значений
Во всех браузерах кроме Safari вычисляемые значения можно увидеть, просто наведя указатель мыши на переменную. В Safari для этого нужно щёлкнуть по кнопке с парой полосок.
При работе над большими проектами сложно запомнить имена всех используемых в них CSS-переменных. Но благодаря возможностям по автозавершению ввода, доступных в браузерах Chrome, Firefox и Edge, это — не проблема.
![](https://habrastorage.org/r/w780q1/getpro/habr/post_images/aa0/85f/6f8/aa085f6f8f238217a46aecd27027d9b7.jpg)
Автозавершение ввода имени переменной
Для того чтобы этот механизм заработал — достаточно начать вводить имя переменной.
Если CSS-переменную нужно отключить от всех элементов, которые её используют, для этого достаточно снять флажок, находящийся напротив переменной в том элементе, где она объявлена.
![](https://habrastorage.org/r/w780q1/getpro/habr/post_images/3b7/7cc/24c/3b77cc24ca081cdcce05b4c05571a695.jpg)
Флажки для отключения CSS-переменных
Я рассказал довольно много всего о CSS-переменных. Надеюсь, вам пригодится то, что вы сегодня узнали.
Пользуетесь ли вы CSS-переменными в своих проектах?
![](https://habrastorage.org/r/w1560/webt/ou/g5/kh/oug5kh6sjydt9llengsiebnp40w.png)
![](https://habrastorage.org/r/w1560/webt/3p/iw/1j/3piw1j3wd_cgmzq9sefgferaumu.png)
![](https://habrastorage.org/webt/am/sd/sl/amsdsl3qgw4_ursgt9kzvseaot4.png)
Я написал эту статью для того чтобы собрать в ней всё, что я знаю о CSS-переменных. В ходе работы над ней я надеялся узнать о них что-то новое и упорядочить то, что мне уже известно. Вы найдёте в этом материале всё, что нужно знать о CSS-переменных. Здесь имеется множество практических примеров и описаний сценариев использования CSS-переменных.
Готовы? Если так — приступим.
Введение
CSS-переменные — это значения, которые объявляют в CSS, преследуя две цели. Первая — это многократное использование таких значений. Вторая — это сокращение объёмов CSS-кода. Рассмотрим простой пример.
![](https://habrastorage.org/getpro/habr/post_images/5db/fae/ecc/5dbfaeecc34e27af4ffb682d752ad66f.png)
Стилизация элементов страницы
.section {
border: 2px solid #235ad1;
}
.section-title {
color: #235ad1;
}
.section-title::before {
content: "";
display: inline-block;
width: 20px;
height: 20px;
background-color: #235ad1;
}
В этом примере CSS-кода значение
#235ad1
используется три раза. Представьте себе, что это — часть большого проекта. В нём подобные стили разбросаны по множеству CSS-файлов. Вас попросили поменять цвет #235ad1
. В такой ситуации лучшее, что можно сделать, заключается в том, чтобы прибегнуть к возможностям редакторов кода по поиску и замене строковых значений.Но при использовании CSS-переменных подобные задачи решаются гораздо проще. Давайте поговорим о том, как объявлять CSS-переменные. Перед именем переменной должно идти два дефиса. Объявим переменную в стиле для псевдокласса
:root
элемента <html>
::root {
--color-primary: #235ad1;
}
.section {
border: 2px solid var(--color-primary);
}
.section-title {
color: var(--color-primary);
}
.section-title::before {
/* Другие стили */
background-color: var(--color-primary);
}
По-моему, этот фрагмент кода выглядит гораздо чище, чем предыдущий. Переменная
--color-primary
является глобальной, так как объявлена она в стиле для псевдокласса :root
. Но CSS-переменные можно объявлять и на уровне отдельных элементов, ограничивая область их видимости в документе.Именование переменных
Правила именования CSS-переменных не особенно сильно отличаются от правил, принятых в различных языках программирования. А именно, правильное имя CSS-переменной может включать в себя алфавитно-цифровые символы, знаки подчёркивания и дефисы. Кроме того, стоит обратить внимание на то, что имена этих переменных чувствительны к регистру.
/* Правильные имена */
:root {
--primary-color: #222;
--_primary-color: #222;
--12-primary-color: #222;
--primay-color-12: #222;
}
/* Неправильные имена */
:root {
--primary color: #222; /* Пробелы использовать нельзя */
--primary$%#%$#
}
Область видимости переменных
CSS-переменные имеют одну полезную особенность, которая заключается в том, что область их видимости можно ограничивать. В основе этой идеи лежат те же принципы, которые применяются в различных языках программирования. Например — в JavaScript:
let element = "cool";
function cool() {
let otherElement = "Not cool";
console.log(element);
}
В этом примере переменная
element
является глобальной, она доступна в функции cool()
. Но к переменной otherElement
можно обратиться только из тела функции cool()
. Рассмотрим эту идею в применении к CSS-переменным.:root {
--primary-color: #235ad1;
}
.section-title {
--primary-color: d12374;
color: var(--primary-color);
}
Переменная
--primary-color
является глобальной, обратиться к ней можно из любого элемента документа. Если переопределить её в блоке .section-title
, это приведёт к тому, что её новым значением можно будет пользоваться только в этом блоке.Вот схема, разъясняющая эту идею.
![](https://habrastorage.org/getpro/habr/post_images/e1b/0a3/1f2/e1b0a31f2f0135e0a40efb157803c861.png)
Область видимости CSS-переменных
Тут показана переменная
--primary-color
, используемая для настройки цвета заголовков разделов. Нам нужно настроить цвет заголовков разделов со сведениями об избранных авторах и о свежих статьях. Поэтому в стилях этих разделов мы переопределяем данную переменную. То же самое происходит и с переменной --unit
. Вот стили, на которых основана предыдущая схема./* Глобальные переменные */
:root {
--primary-color: #235ad1;
--unit: 1rem;
}
/* Для цвета и отступа применяются глобальные значения */
.section-title {
color: var(--primary-color);
margin-bottom: var(--unit);
}
/* Переопределение переменной, управляющей цветом */
.featured-authors .section-title {
--primary-color: #d16823;
}
/* Переопределение переменных, управляющими цветом и отступом */
.latest-articles .section-title {
--primary-color: #d12374;
--unit: 2rem;
}
Использование резервных значений
Обычно «резервные значения» используются для обеспечения работоспособности сайтов в браузерах, которые не поддерживают некие современные CSS-механизмы. Но здесь речь пойдёт не об этом, а о том, как задавать значения, используемые в том случае, если нужные CSS-переменные оказываются недоступными. Рассмотрим следующий пример:
.section-title {
color: var(--primary-color, #222);
}
Обратите внимание на то, что функции
var()
передано несколько значений. Второе из них, #222
, будет использовано только в том случае, если переменная --primary-color
не будет определена. При указании резервных значений можно использовать и вложенные конструкции var()
:.section-title {
color: var(--primary-color, var(--black, #222));
}
Этот подход к работе с переменными может оказаться полезным в том случае, если значение переменной зависит от некоего действия. Если может случиться так, что в переменной не будет значения, важно предусмотреть использование резервного значения.
Примеры и сценарии использования CSS-переменных
▍Управление размером компонентов
![](https://habrastorage.org/getpro/habr/post_images/7c5/049/119/7c5049119f4338288b61481e806cf007.png)
Компоненты разных размеров
В дизайн-системах часто имеются, например, кнопки разных размеров. Как правило, речь идёт о трёх вариантах размеров (маленький, обычный, большой). С использованием CSS-переменных можно очень легко описывать такие кнопки и другие подобные элементы.
.button {
--unit: 1rem;
padding: var(--unit);
}
.button--small {
--unit: 0.5rem;
}
.button--large {
--unit: 1.5rem;
}
Меняя значение переменной
--unit
в области видимости, соответствующей компоненту кнопки, мы создаём разные варианты кнопки.▍CSS-переменные и HSL-цвета
HSL (Hue, Saturation, Lightness — тон, насыщенность, светлота) — это цветовая модель, в которой компонент H определяет цвет, а компоненты S и L определяют параметры насыщенности и светлоты цвета.
![](https://habrastorage.org/getpro/habr/post_images/d46/6b8/5b1/d466b85b180659315457ceb1cbf10c10.png)
Цвета элементов, задаваемые с использованием HSL
:root {
--primary-h: 221;
--primary-s: 71%;
--primary-b: 48%;
}
.button {
background-color: hsl(var(--primary-h), var(--primary-s), var(--primary-b));
transition: background-color 0.3s ease-out;
}
/* Затемнение фона */
.button:hover {
--primary-b: 33%;
}
Обратите внимание на то, как я сделал цвет кнопки темнее, уменьшив значение переменной
--primary-b
.Если вас интересует тема использования цветов в CSS — вот моя статья об этом.
▍Изменение размеров элементов с сохранением пропорций
Если вы работали в какой-нибудь дизайнерской программе, вроде Photoshop, Sketch, Figma или Adobe XD, то вы можете знать об использовании клавиши
Shift
при изменении размеров объектов. Благодаря этому приёму можно избежать искажения пропорций элементов.В CSS нет стандартного механизма изменения размеров элементов с сохранением пропорций. Но это ограничение можно обойти, воспользовавшись, как несложно догадаться, CSS-переменными.
![](https://habrastorage.org/getpro/habr/post_images/b68/582/ff4/b68582ff4723bcd0a0a419db2e291e81.png)
Настройка размеров элемента с помощью CSS-переменных
Предположим, что у нас имеется значок, ширина и высота которого должны быть одинаковыми. Для того чтобы этого добиться, я определил CSS-переменную
--size
, использовав её для настройки ширины и высоты элемента..icon {
--size: 22px;
width: var(--size);
height: var(--size);
}
В результате оказывается, что этот приём имитирует использование клавиши
Shift
при изменении размеров объектов. Тут достаточно изменить значение одной переменной --size
. Подробнее эта тема освещена здесь.▍Макеты, основанные на CSS Grid
CSS-переменные могут оказаться чрезвычайно полезными при проектировании макетов страниц, основанных на CSS Grid. Представьте, что вам нужно сделать так, чтобы Grid-контейнер выводил бы дочерние элементы, основываясь на заранее заданной ширине элементов. Вместо того чтобы создавать класс для каждого варианта представления элементов, что приведёт к необходимости дублирования CSS-кода, эту задачу можно решить, воспользовавшись CSS-переменными.
![](https://habrastorage.org/getpro/habr/post_images/1d3/192/ee2/1d3192ee2ba2efe9fb9e4ef3510e4d56.png)
Настройка размеров Grid-элементов с использованием CSS-переменной
.wrapper {
--item-width: 300px;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--item-width), 1fr));
grid-gap: 1rem;
}
.wrapper-2 {
--item-width: 500px;
}
Благодаря такому подходу можно создать гибкий Grid-макет, подходящий для использования в различных проектах, который легко поддерживать. Ту же идею можно применить и для настройки свойства
grid-gap
..wrapper {
--item-width: 300px;
--gap: 0;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--item-width), 1fr));
}
.wrapper.gap-1 {
--gap: 16px;
}
![](https://habrastorage.org/getpro/habr/post_images/7a9/ab0/d15/7a9ab0d152eccf72f2a848eadc33eb0e.png)
Использование переменной --gap для настройки свойства grid-gap
Хранение в переменных значений со сложной структурой
▍CSS-градиенты
Под «значениями со сложной структурой» я понимаю, например, нечто вроде градиентов. Если в проекте есть градиент или фон, используемые во многих местах этого проекта, то их описания имеет смысл хранить в CSS-переменных.
:root {
--primary-gradient: linear-gradient(150deg, #235ad1, #23d1a8);
}
.element {
background-image: var(--primary-gradient);
}
В подобных ситуациях в переменных можно хранить и отдельные элементы «сложных» значений. Это, например, может быть угол градиента:
.element {
--angle: 150deg;
background-image: linear-gradient(var(--angle), #235ad1, #23d1a8);
}
.element.inverted {
--angle: -150deg;
}
![](https://habrastorage.org/getpro/habr/post_images/9bc/72a/ec6/9bc72aec619db7ad2b70d60a3af62e1b.png)
Разные варианты градиента, созданные путём изменения переменной --angle
▍Позиция фона
Как уже было сказано, CSS-переменные могут хранить значения со сложной структурой. Это может оказаться полезным в том случае, если имеется элемент, который, в зависимости от происходящего, может понадобиться размещать в разных местах страницы.
![](https://habrastorage.org/getpro/habr/post_images/1d0/2d8/910/1d02d8910827af2e2e89251ba2f74976.png)
Управление позицией элемента с помощью переменной --pos
.table {
--size: 50px;
--pos: left center;
background: #ccc linear-gradient(#000, #000) no-repeat;
background-size: var(--size) var(--size);
background-position: var(--pos);
}
Переключение между тёмной и светлой темами
Сейчас сайты, почти в обязательном порядке, оснащают тёмной и светлой темой. Для решения этой задачи можно воспользоваться CSS-переменными, храня в них сведения о цветах и переключаясь между ними после анализа системных параметров или настроек, выполненных пользователем.
![](https://habrastorage.org/getpro/habr/post_images/8fc/a27/03d/8fca2703dab6ef3ab37330d3b3bff0c2.png)
Светлая и тёмная темы
:root {
--text-color: #434343;
--border-color: #d2d2d2;
--main-bg-color: #fff;
--action-bg-color: #f9f7f7;
}
/* Класс, добавленный к элементу <html> */
.dark-mode {
--text-color: #e9e9e9;
--border-color: #434343;
--main-bg-color: #434343;
--action-bg-color: #363636;
}
Вот видеодемонстрация вышеозвученной идеи.
Установка значений, применяемых по умолчанию
В некоторых ситуациях нужно задавать CSS-переменные с использованием JavaScript. Представим, что нам нужно установить значение свойства
height
элемента, размеры которого могут меняться. Я узнал о данном приёме из этой статьи.Переменная
--details-height-open
изначально пуста. Её планируется использовать в описании стиля некоего элемента. Она должна содержать высоту элемента в пикселях. Если из JavaScript установить значение этой переменной по какой-то причине не удастся, важно предусмотреть применение вместо неё некоего резервного значения, используемого по умолчанию..section.is-active {
max-height: var(--details-height-open, auto);
}
В этом примере роль значения, используемого по умолчанию, играет
auto
. Оно будет применено в том случае, если из JavaScript не удастся задать значение переменной --details-height-open
.Регулирование ширины элемента-контейнера
![](https://habrastorage.org/getpro/habr/post_images/c07/535/b68/c07535b68c1681406b9855ea5d1660ef.png)
Управление шириной элемента-контейнера
Элементы-контейнеры, используемые на веб-страницах, могут, в разных ситуациях, иметь разные размеры. Возможно, на одной странице может понадобиться небольшой контейнер, а на другой — контейнер побольше. В подобных случаях CSS-переменные могут с успехом использоваться для управления размерами контейнеров.
.wrapper {
--size: 1140px;
max-width: var(--size);
}
.wrapper--small {
--size: 800px;
}
Встроенные стили
Использование CSS-переменных во встроенных стилях может открыть перед фронтенд-разработчиком массу новых возможностей, о которых он раньше и не подозревал. На самом деле, я написал об этом целую статью, но тут я, всё же, расскажу о самых интересных способах использования переменных во встроенных стилях.
Возможно, в продакшне этими методами лучше не пользоваться. Они очень хорошо подходят для прототипирования и для исследования различных дизайнерских идей.
▍Динамические Grid-элементы
Например, для настройки ширины элемента можно воспользоваться переменной
--item-width
, объявленной прямо в атрибуте элемента style
. Такой подход может оказаться полезным при прототипировании Grid-макетов.Вот HTML-код элемента:
<div class="wrapper" style="--item-width: 250px;">
<div></div>
<div></div>
<div></div>
</div>
Вот стиль, применяемый к этому элементу:
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--item-width), 1fr));
grid-gap: 1rem;
}
Здесь можно поэкспериментировать с примером к этому разделу.
▍Аватары пользователей
![](https://habrastorage.org/getpro/habr/post_images/11c/2d5/31a/11c2d531a1228117536cf86ca102f9e2.png)
Аватары разных размеров
Ещё один интересный вариант использования CSS-переменных во встроенных стилях представлен созданием элементов разных размеров. Предположим, нам, в разных ситуациях, нужно выводить аватар пользователя различных размеров. При этом мы хотим управлять его размером с использованием единственной CSS-переменной.
Вот разметка:
<img src="user.jpg" alt="" class="c-avatar" style="--size: 1" />
<img src="user.jpg" alt="" class="c-avatar" style="--size: 2" />
<img src="user.jpg" alt="" class="c-avatar" style="--size: 3" />
<img src="user.jpg" alt="" class="c-avatar" style="--size: 4" />
Вот стили:
.c-avatar {
display: inline-block;
width: calc(var(--size, 1) * 30px);
height: calc(var(--size, 1) * 30px);
}
Проанализируем эти стили:
- У нас имеется конструкция
var(--size, 1)
. В ней предусмотрено значение, применяемое по умолчанию. Оно используется в том случае, если значение переменной--size
не задано с использованием атрибутаstyle
стилизуемого элемента. - Минимальный размер элемента устанавливается равным
30px*30px
.
Медиазапросы
Совместное использование CSS-переменных и медиазапросов может принести немалую пользу в деле настройки значений переменных, используемых на всех страницах веб-сайтов. Самый простой пример использования этой техники, который приходит мне в голову, заключается в настройке расстояния между элементами:
:root {
--gutter: 8px;
}
@media (min-width: 800px) {
:root {
--gutter: 16px;
}
}
В результате свойства любого элемент, в котором используется переменная
--gutter
, будут зависеть от ширины области просмотра браузера. Как по мне, так это — просто замечательная возможность.Наследование
CSS-переменные поддерживают наследование. Если в пределах родительского элемента объявлена CSS-переменная, то элементы-потомки наследуют эту переменную. Рассмотрим пример.
Вот HTML-код:
<div class="parent">
<p class="child"></p>
</div>
Вот стили:
.parent {
--size: 20px;
}
.child {
font-size: var(--size);
}
Элемент
.child
наследует переменную --size
, объявленную в стиле элемента .parent
. У элемента .child
есть доступ к этой переменной. Полагаю, это — очень интересно. Возможно, вы сейчас задаётесь вопросом о том, какая нам от этого польза. Полагаю, ответить на этот вопрос поможет следующий пример из жизни.![](https://habrastorage.org/getpro/habr/post_images/f9d/6b5/3d1/f9d6b53d1178adafdca94b31057c6a25.png)
Наследование CSS-переменных
Тут имеется группа кнопок, к которым предъявляются следующие требования:
- Возможность изменения размера всех элементов путём установки значения единственной переменной.
- Расстояние между элементами должно динамически меняться в зависимости от их размера. При увеличении элементов расстояние между ними увеличивается, а при уменьшении — уменьшается.
Вот разметка к этому примеру:
<div class="actions">
<div class="actions__item"></div>
<div class="actions__item"></div>
<div class="actions__item"></div>
</div>
Вот стили:
.actions {
--size: 50px;
display: flex;
gap: calc(var(--size) / 5);
}
.actions--m {
--size: 70px;
}
.actions__item {
width: var(--size);
height: var(--size);
}
Обратите внимание на то, как я использовал переменную
--size
при настройке свойства gap
Flexbox-элементов. Это позволяет, основываясь на переменной --size
, динамически менять расстояние между элементамиЕщё один пример использования механизма наследования CSS-переменных представлен настройкой CSS-анимаций. Этот пример я взял отсюда.
@keyframes breath {
from {
transform: scale(var(--scaleStart));
}
to {
transform: scale(var(--scaleEnd));
}
}
.walk {
--scaleStart: 0.3;
--scaleEnd: 1.7;
animation: breath 2s alternate;
}
.run {
--scaleStart: 0.8;
--scaleEnd: 1.2;
animation: breath 0.5s alternate;
}
При таком подходе нам не нужно дважды объявлять
@keyframes
. В стилях .walk
и .run
переопределяются значения унаследованных переменных.Валидация CSS-переменных
Если оказывается, что с CSS-переменной, переданной функции
var()
, что-то не так, браузер заменит значение этой переменной на исходное (унаследованное) значение соответствующего свойства.:root {
--main-color: 16px;
}
.section-title {
color: var(--main-color);
}
Здесь в переменную
--main-color
, используемую для настройки свойства color
, записано значение 16px
. А это — совершенно неправильно. Свойство color
наследуется. Браузер в этой ситуации работает по следующему алгоритму:- Является ли свойство наследуемым?
Вот схема работы браузера.
![](https://habrastorage.org/getpro/habr/post_images/b4f/a45/8de/b4fa458defe561b2e8fb8c85e55e9dbc.png)
Схема работы браузера при обнаружении некорректного значения CSS-переменной
▍Концепция недопустимого значения, появляющегося во время вычислений
То, о чём шла речь выше, с технической точки зрения, называется «недопустимым значением, появляющимся во время вычислений» (Invalid At Computed-Value Time). Ситуация, в которой появляются такие значения, возникает, когда функции
var()
передаётся корректная CSS-переменная, значение которой не подходит для записи в настраиваемое с её помощью свойство.Рассмотрим следующий пример, который я взял из этой статьи:
.section-title {
top: 10px;
top: clamp(5px, var(--offset), 20px);
}
Если браузер не поддерживает функцию
clamp()
— воспользуется ли он, в качестве резервного, значением, заданным в конструкции top: 10px
? Если кратко ответить на этот вопрос, то нет — не воспользуется. Причина этого заключается в том, что к тому моменту, когда браузер обнаружит некорректное значение, которое пытаются записать в свойство, он уже отбросит, в соответствии с порядком каскадного применения стилей, другие значения. То есть — он просто проигнорирует конструкцию top: 10px
.Вот что говорится об этом в спецификации CSS:
Концепция появления недопустимого значения во время вычислений существует из-за того, что ошибки, связанные с переменными, не проявляются, в отличие от других синтаксических ошибок, на ранних стадиях работы системы. Поэтому оказывается, что когда пользовательский агент обнаружит, что значение переменной некорректно, он уже отбросит, в соответствии с порядком каскадного применения стилей, другие значения.
В результате оказывается, что если нужно применять возможности CSS, не пользующиеся широкой поддержкой браузеров, при реализации которых используются CSS-переменные, нужно применять директиву
@supports
. Вот как это сделано в вышеупомянутой статье:@supports (top: max(1em, 1px)) {
#toc {
top: max(0em, 11rem - var(--scrolltop) * 1px);
}
}
Интересные находки
▍Хранение URL в переменных
Возможно, некоторые ресурсы, используемые на ваших веб-страницах, нужно загружать из внешних источников. В подобных ситуациях можно хранить URL этих ресурсов в CSS-переменных.
:root {
--main-bg: url("https://example.com/cool-image.jpg");
}
.section {
background: var(--main-bg);
}
Тут может возникнуть вопрос о том, можно ли обрабатывать конструкции вида
var(--main-bg)
с помощью CSS-функции url()
. Рассмотрим следующий пример::root {
--main-bg: "https://example.com/cool-image.jpg";
}
.section {
background: url(var(--main-bg));
}
Так поступить не получится, так как функция
url()
воспринимает всю конструкцию var(--main-bg)
в виде URL, а это неправильно. К тому моменту, когда браузер вычислит значение, оно уже будет некорректным, рассмотренная конструкция не будет работать так, как ожидается.▍Хранение нескольких значений
В CSS-переменных можно хранить несколько значений. Если это — значения, выглядящие так, как они должны выглядеть в том месте, где планируется использовать переменную, то такая конструкция окажется работоспособной. Рассмотрим пример.
![](https://habrastorage.org/getpro/habr/post_images/366/428/ac7/366428ac76b2fdbee88aa96c07e4f0fb.png)
Значение переменной выглядит так, как ожидается
Вот CSS-код:
:root {
--main-color: 35, 90, 209;
}
.section-title {
color: rgba(var(--main-color), 0.75);
}
Здесь имеется функция
rgba()
и RGB-значения, разделённые запятой и записанные в CSS-переменную. Эти значения используются при задании цвета. При таком подходе к использованию функции rgba()
у разработчика появляется возможность воздействовать на значение, соответствующее альфа-каналу цвета, настраивая цвет различных элементов.Единственный минус такого подхода заключается в том, что цвет, задаваемый функцией
rgba()
, нельзя будет настраивать, пользуясь инструментами разработчика браузера. Если при работе над вашим проектом эта возможность важна — вам, вероятно, не подойдёт вышеописанный способ использования функции rgba()
.Вот пример использования CSS-переменной для настройки свойства
background
::root {
--bg: linear-gradient(#000, #000) center/50px;
}
.section {
background: var(--bg);
}
.section--unique {
background: var(--bg) no-repeat;
}
Здесь показана стилизация двух разделов сайта. Фон одного из них не должен повторяться по осям
x
и y
.▍Изменение значений CSS-переменных в теле правила @keyframes
Если вы читали спецификацию, посвящённую CSS-переменным, то вы могли столкнуться там с термином «animation-tainted». С его помощью описывают тот факт, что значения CSS-переменных не поддаются плавному изменению в правиле
@keyframes
. Рассмотрим пример.Вот HTML-код:
<div class="box"></div>
Вот стили:
.box {
width: 50px;
height: 50px;
background: #222;
--offset: 0;
transform: translateX(var(--offset));
animation: moveBox 1s infinite alternate;
}
@keyframes moveBox {
0% {
--offset: 0;
}
50% {
--offset: 50px;
}
100% {
--offset: 100px;
}
}
Анимация в этом случае не будет плавной. Переменная примет лишь три значения:
0
, 50px
и 100px
. В спецификации CSS говорится, что любое пользовательское свойство, использованное в правиле @keyframes
, становится animation-tainted-свойством, что влияет на то, как оно обрабатывается посредством функции var()
при анимировании элементов.Если нам нужно обеспечить в предыдущем примере плавную анимацию, то делать это надо так, как делалось раньше. То есть — надо заменить переменную на те CSS-свойства элемента, которые нужно анимировать.
@keyframes moveBox {
0% {
transform: translateX(0);
}
50% {
transform: translateX(50px);
}
100% {
transform: translateX(100px);
}
}
→ Вот пример
Хочу отметить, что после публикации этой статьи мне сообщили о том, что анимировать CSS-переменные в
@keyframes
, всё же, можно. Но для этого переменные надо регистрировать с использованием правила @property
. Пока эта возможность поддерживается лишь браузерами, основанными на Chromium.@property --offset {
syntax: "<length-percentage>";
inherits: true;
initial-value: 0px;
}
Здесь можно поэкспериментировать с примером применения этой возможности.
▍Вычисления
Возможно, вы не знаете о том, что CSS-переменные можно использовать в вычислениях. Взглянем на пример, который мы уже рассматривали, говоря об аватарах:
.c-avatar {
display: inline-block;
width: calc(var(--size, 1) * 30px);
height: calc(var(--size, 1) * 30px);
}
Размеры аватара зависят от значения переменной
--size
. Значением, используемым по умолчанию, является 1
. Это значит, что стандартным размером аватара является 30px*30px
. Обратите внимание на следующие стили и на то, что изменение этой переменной приводит к изменению размера аватара..c-avatar--small {
--size: 2;
}
.c-avatar--medium {
--size: 3;
}
.c-avatar--large {
--size: 4;
}
Инструменты разработчика различных браузеров и CSS-переменные
При использовании инструментов разработчика различных браузеров можно применять некоторые полезные приёмы, которые упрощают работу с CSS-переменными. Поговорим о них.
▍Просмотр цветов, задаваемых с помощью переменных
Я считаю полезной возможность видеть цвет, описываемый CSS-переменной. Эта возможность доступна в браузерах Chrome и Edge.
![](https://habrastorage.org/getpro/habr/post_images/e91/dbc/d2c/e91dbcd2c53dee88f5bed196512af93f.jpg)
Просмотр цвета, задаваемого CSS-переменной
▍Вычисляемые значения
Для того чтобы взглянуть на вычисляемое значение CSS-переменной нужно, в зависимости от браузера, навести на переменную указатель мыши или щёлкнуть мышью по специальной кнопке.
![](https://habrastorage.org/getpro/habr/post_images/bde/a5b/26b/bdea5b26b12bf6cb648c57833bda809c.jpg)
Просмотр вычисляемых значений
Во всех браузерах кроме Safari вычисляемые значения можно увидеть, просто наведя указатель мыши на переменную. В Safari для этого нужно щёлкнуть по кнопке с парой полосок.
▍Автозавершение ввода
При работе над большими проектами сложно запомнить имена всех используемых в них CSS-переменных. Но благодаря возможностям по автозавершению ввода, доступных в браузерах Chrome, Firefox и Edge, это — не проблема.
![](https://habrastorage.org/getpro/habr/post_images/aa0/85f/6f8/aa085f6f8f238217a46aecd27027d9b7.jpg)
Автозавершение ввода имени переменной
Для того чтобы этот механизм заработал — достаточно начать вводить имя переменной.
▍Отключение CSS-переменных
Если CSS-переменную нужно отключить от всех элементов, которые её используют, для этого достаточно снять флажок, находящийся напротив переменной в том элементе, где она объявлена.
![](https://habrastorage.org/getpro/habr/post_images/3b7/7cc/24c/3b77cc24ca081cdcce05b4c05571a695.jpg)
Флажки для отключения CSS-переменных
Итоги
Я рассказал довольно много всего о CSS-переменных. Надеюсь, вам пригодится то, что вы сегодня узнали.
Пользуетесь ли вы CSS-переменными в своих проектах?
![](https://habrastorage.org/webt/ou/g5/kh/oug5kh6sjydt9llengsiebnp40w.png)
![](https://habrastorage.org/webt/3p/iw/1j/3piw1j3wd_cgmzq9sefgferaumu.png)