Переменные CSS (также известные как настраиваемые свойства) поддерживаются браузерами почти 4 года. Мне нравится применять их в зависимости от проекта или ситуации. Они очень полезны и просты в использовании, но зачастую фронтенд разработчик неправильно использует или неправильно понимает их.
Основная цель статьи: я хочу иметь место, где лежит все, что я знаю о переменных CSS, чтобы узнать и понять больше. Здесь вы прочитаете обо всем, что должны знать о переменных CSS, включая примеры применения в коде. Вы готовы? Тогда погружаемся.
Введение
Переменные CSS это значения, определенные в документе CSS с целью переиспользования и уменьшения количества избыточных значений CSS. Простой пример:
.section { border: 2px solid #235ad1;}.section-title { color: #235ad1;}.section-title::before { content: ""; display: inline-block; width: 20px; height: 20px; background-color: #235ad1;}
В этом фрагменте
#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 { /* Other styles */ background-color: var(--color-primary);}
Не так много кода и он чище кода выше, правда? Переменная
--color-primary
глобальная, потому что определена в
элементе :root
. Но возможно ограничивать область
действия переменных.Именование переменных
Именование CSS не так уж отличается от именования переменных в языках программирования. Корректное имя переменной может содержать латинские буквы и цифры, подчеркивания, тире. Важно упомянуть, что переменные CSS чувствительны к регистру.
/* Valid names */:root {--primary-color: #222;--_primary-color: #222;--12-primary-color: #222;--primay-color-12: #222;}/* Invalid names */:root {--primary color: #222; /* Spacings are not allowed */--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
, ее новое значение
работает только там. Визуальный пример показывает лучше:Мы имеем
--primary-color
, используемую для цвета
заголовка раздела. Мы можем настроить цвет для избранных авторов и
последнего раздела статьи, когда переопределяем их. То же применимо
к переменной --unit
. Вот CSS для рисунка выше:
/* Global variables */:root { --primary-color: #235ad1; --unit: 1rem;}/* Section title default color and spacing */.section-title { color: var(--primary-color); margin-bottom: var(--unit);}/* Overrding the section title color */.featured-authors .section-title { --primary-color: #d16823;}/* Overrding the section title color & spacing */.latest-articles .section-title { --primary-color: #d12374; --unit: 2rem;}
Резервные значения
Резервное значение не означает, что мы обеспечиваем значение для браузера, который не поддерживает CSS. Эту возможность мы можем использовать с помощью переменных CSS. Посмотрите на пример:
.section-title { color: var(--primary-color, #222);}
Обратите внимание: функция
var()
имеет несколько
значений. Второй вариант #222
работает только тогда,
когда переменная --primary-color
по какой-то причине
не определена. Мало того, мы можем вложить var()
в
другую var()
.
.section-title { color: var(--primary-color, var(--black, #222));}
Эта особенность полезна, когда значение зависит от определенного действия. Резервное значение важно предоставить, когда у переменной нет значения.
Примеры использования
Управление размером компонента
Обычное дело иметь несколько размеров кнопки в дизайн-системе: маленький, средний и большой. Размеры проще описать с помощью переменной CSS.
.button { --unit: 1rem; padding: var(--unit);}.button--small { --unit: 0.5rem;}.button--large { --unit: 1.5rem;}
Изменяя значение
--unit
внутри области видимости
компонента кнопки мы создаем разные варианты кнопки.Переменные CSS и цвета HSL
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;}/* Making the background darker */.button:hover { --primary-b: 33%;}
Обратите внимание, как темнеет кнопка с уменьшением значения переменной --primary-b.
Если хочется узнать больше о цветах в CSS, я написал о них подробную статью .
Пропорциональное изменение размера
Если вы работали с Photoshop, Sketch, Figma или Adobe XD, то у вас может возникнуть идея удерживать клавишу
Shift
для
пропорционального изменения размера элемента. В CSS нельзя сделать
такое напрямую, но есть обходной путь с применением переменных
CSS.Предположим, есть иконка, которая должна быть квадратной. Я определил переменную
--size
и использовал ее как для
ширины, так и для высоты.
.icon { --size: 22px; width: var(--size); height: var(--size);}
Вот оно! Теперь вы можете имитировать эффект Shift, изменяя только значение переменной
--size
. Вы можете узнать больше об
этом
здесь.CSS 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-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;}
Сохранение наполненных значений
Градиенты 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;}
Положение фона
Возможно включить значения в переменную. Это полезно, когда элемент позиционируется в зависимости от контекста.
.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 мы можем хранить две их версии и переключаться между ними в зависимости от предпочтений пользователя или системных настроек.
:root { --text-color: #434343; --border-color: #d2d2d2; --main-bg-color: #fff; --action-bg-color: #f9f7f7;}/* A class added to the <html> element*/.dark-mode { --text-color: #e9e9e9; --border-color: #434343; --main-bg-color: #434343; --action-bg-color: #363636;}
Установка значения по умолчанию
Иногда нужно установить переменную CSS с помощью JavaScript . Например, нужно получить высоту расширяемого компонента. Я узнал об этой технике из статьи Майкла Шарнагла.
Переменная
--details-height-open
пуста. Она
добавляется к определенному элементу HTML. Он будет содержать
пиксельное значение. Когда по какой-то причине Javascript не
работает, важно указать правильное значение по умолчанию или
резервное значение.
.section.is-active { max-height: var(--details-height-open, auto);}
Значение
auto
это резервное значение на случай сбоя
JavaScript и отсутствия переменной CSS
--details-height-open
.Управление шириной враппера
Враппер веб-сайта может иметь несколько вариантов. Может быть, вам нужна небольшая обертка для страницы, но большая для другой. В таком случае полезны переменные CSS.
.wrapper { --size: 1140px; max-width: var(--size);}.wrapper--small { --size: 800px;}
Встроенные стили
Переменные CSS со встроенными стилями открывают множество возможностей, о которых вы, возможно, не знали. Об этом я написал статью, но здесь я упомяну некоторые интересные варианты применения. Возможно, такой подход не идеален для реально работающих веб-сайтов, но он может быть полезен при создании прототипов и в тестировании различных идей.
Элементы динамической сетки
Добавляем переменную
--item-width
внутри атрибута
style и все. Такой подход помогает, например, в создании прототипов
сеток.
<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;}
Демо
Аватары пользователей
Полезный вариант применения определение размеров элементов. Допустим, нужно четыре разных размера аватара пользователя с возможностью контроля размера с помощью только одной переменной.
<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);}
Проанализируем CSS выше:
- Во-первых, у нас есть
var(--size, 1)
. Я добавил резервное значение на случай, если оно не добавлено в атрибут style. - Минимальный размер аватара 30*30 пикселей.
Медиа-запросы
Комбинирование переменных CSS и медиа-запросов очень полезно в настройке переменных, применяемых на всем веб-сайте. Самый простой пример, о котором я думаю, изменение значения отступов.
:root { --gutter: 8px;}@media (min-width: 800px) { :root { --gutter: 16px; }}
Любой элемент с
--gutter
, изменит отступ в зависимости
от размера области просмотра. Разве это не здорово?Наследование
Да, переменные CSS наследуются. Если в родительском элементе определена переменная, дочерние элементы наследуют ее. Пример:
<div class="parent"> <p class="child"></p></div>
.parent { --size: 20px;}.child { font-size: var(--size);}
Элемент
.child
будет иметь доступ к переменной --size
в результате наследования ее от своего родителя. Интересно, правда?
Как извлечь из этого пользу? Что ж, вот пример из жизни.У нас есть группа действий с такими требованиями:
- Возможность изменять размер всех элементов, изменяя только одну переменную.
- Интервал должен быть динамическим (сжиматься при уменьшении размера элемента и увеличиваться при увеличении размера элемента).
<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 используется для свойства зазора
flexbox
. Это означает, что интервал может быть
динамическим и будет зависеть от переменной
--size
.Другой полезный пример наследование переменных CSS для настройки анимации. Ниже вы видите пример из этой статьи Сандрины Перейры в блоге CSS Tricks.
@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);}
Я использовал 16 пикселей это значение свойства цвета. Значение неправильное. Поскольку свойство цвета наследуются, вот, что сделает браузер:
- Свойство наследуемо?
- Если да, есть ли у родителя это свойство?
- Да: значение наследуется
- Нет: устанавливается по умолчанию
- Если нет, устанавливается начальное значение
Диаграмма показывает работу браузера:
Некорректное вычисленное значение
Вышеупомянутое технически называется некорректное вычисленное значение. Это происходит, когда
var()
ссылается на переменную CSS ее начальным
значением или использует допустимую переменную CSS с недопустимым
значением свойства.Посмотрим на пример, о котором я узнал из этой статьи пользователя Lea Verou.
.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(http://personeltest.ru/aways/example.com/cool-image.jpg);}.section { background: var(--main-bg);}
Можно задаться вопросом: можно ли интерполировать CSS-переменные с помощью url(). Посмотрим на пример:
:root { --main-bg: https://example.com/cool-image.jpg;}.section { background: url(var(--main-bg));}
Это невозможно:
var(--main-bg)
рассматривается как сам
URL, который недопустим. К тому моменту, когда браузер вычислит это
значение, оно уже не будет действительным и не будет работать, как
ожидалось.Хранение нескольких значений
Полезно то, что возможно хранить несколько значений независимо от значения переменной. Если они невалидны, то это должно сработать. Посмотрим на пример:
:root { --main-color: 35, 90, 209;}.section-title { color: rgba(var(--main-color), 0.75);}
В этом примере у нас есть функция
rgba()
. Значения RGB
хранятся в переменной CSS, разделенной запятой. Это может
обеспечить гибкость в случае, когда вы хотите настроить
прозрачность в зависимости от элемента.Единственный недостаток невозможно настроить значение
rgba
с помощью палитры цветов DevTools. Если это важно
для вашего варианта применения или проекта, то вам, возможно,
придется пересмотреть использование rgba
, как описано
выше.Другой пример применение этого свойства со свойством background.
:root { --bg: linear-gradient(#000, #000) center/50px;}.section { background: var(--bg);}.section--unique { background: var(--bg) no-repeat;}
У нас есть два раздела. Один из них требует, чтобы фон не повторялся по осям X и Y.
Анимация переменных внутри правила
@keyframes
Если вы читали спецификацию для переменных, вы могли прочитать термин animation-tainted испорченная анимация. Идея в том, что при использовании CSS-переменной внутри правила
@keyframes
она не может работать в анимации.
<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
анимируется. Это влияет на то, как оно обрабатывается при обращении
к нему через функцию var()
в свойстве анимации. Когда
хочется, чтобы вышеприведенная анимация работала, мы должны
анимировать по-старому. То есть нужно заменить переменную
фактическим свойством CSS.
@keyframes moveBox { 0% { transform: translateX(0); } 50% { transform: translateX(50px); } 100% { transform: translateX(100px); }}
Обновление: 9 октября 2020 года
Данни Винтер указал, что можно анимировать CSS-переменные внутри ключевых кадров, регистрируя их с помощью
@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);}
У нас могут быть вариации аватара. Я установил значение по умолчанию в 1, поэтому размер по умолчанию равен (30px * 30px). Обратите внимание на различные вариации классов и на то, как изменение значения
--size
приводит к изменению размера
аватара.
.c-avatar--small { --size: 2;}.c-avatar--medium { --size: 3;}.c-avatar--large { --size: 4;}
В DevTools есть несколько полезных трюков, чтобы облегчить нам работу с переменными CSS. Давайте исследуем их!
Возможность увидеть значение цвета
Разве не полезно видеть визуальный индикатор для значения цвета или фона, когда вы используете переменную CSS? Chrome и Edge показывают цвет.
Вычисленные значения
Чтобы увидеть вычисленное значение, наведите указатель мыши или кликните в зависимости от браузера.
Все вычисленные значения отображаются при наведении курсора. За исключением Safari, где для этого нужно нажать кнопку с двумя линиями.
Автозавершение переменных CSS
В большом проекте трудно запомнить все имена переменных. Но можно ввести
--
, какие-то символы и получить список с
переменными CSS на странице. Это работает в Chrome, Firefox и
Edge.Отключение переменной
Когда вам нужно отключить переменную CSS от всех использующих ее элементов, это можно сделать, сняв флажок с элемента, для которого она определена. Смотрите рисунок ниже:
Заключение
Я счастлив, что у меня наконец-то есть для них отдельная страница. Я надеюсь, что вы нашли это полезным, и если да, пожалуйста, поделитесь информацией. Спасибо за чтение!
Я пишу электронную книгу
Рад сообщить вам, что пишу электронную книгу об отладке CSS.
Если вам интересно, перейдите на debuggingcss.com и подпишитесь на обновления о книге.
- Курс Python для веб-разработки
- Профессия Веб-разработчик
- Профессия Java-разработчик с нуля
- Курс по JavaScript
- Профессия iOS-разработчик с нуля
- Профессия Android-разработчик с нуля
- Обучение профессии Data Science с нуля
- Онлайн-буткемп по Data Science
- Обучение профессии Data Analyst с нуля
- Онлайн-буткемп по Data Analytics
- Курс по Machine Learning
- Курс Математика и Machine Learning для Data Science
- Продвинутый курс Machine Learning Pro + Deep Learning
- Курс по аналитике данных
- Курс по DevOps
- Профессия UX-дизайнер с нуля
- Профессия Web-дизайнер