Динамічні властивості CSS дають можливість створювати креативні рішення, натомість значно ускладнюють структуру коду. Отримати максимум користі можливо, використовуючи стратегію структурування СSS з користувацькими властивостями .
Користувацькі СSS-властивості (також відомі як «CSS-змінні») наразі підтримуються усіма сучасними браузерами, тому їх часто можна зустріти у програмних продуктах. Користувацькі властивості відрізняються від змінних у препроцесорах, тому часто їх використовують без розуміння переваг, які вони надають.
Підхід до структурування CSS та навіть взаємодія JavaScript з компонентами UI значно змінюються із використанням користувацьких властивостей. У статті я не буду наголошувати на особливостях синтаксису чи принципах роботи, натомість приділю більше уваги стратегіям отримання максимальної користі від CSS-змінних.
Чим подібні до змінних в препроцесорах?
Користувацькі властивості нагадують змінні в препроцесорах, але мають важливі особливості.
По-перше, найбільш очевидною є різниця у синтаксисі.
З SCSS
ми використовуємо символ $, щоб оголосити змінну:
$s-red: #d33a2c;
З Less
використовуємо символ @:
@s-red: #d33a2c;
Користувацькі властивості застосовують аналогічний підхід, але з префіксом --
:
:root { --s-red: #d33a2c; }
.s-text {
color: var(--s-red);
}
Важливою різницею між користувацькими та препроцесорними змінними є синтаксис присвоєння та повернення значення змінної. Зазвичай, для повернення значення користувацької властивості використовується функція var()
.
Наступна відмінність криється у самій назві. Користувацькі властивості і справді є властивостями CSS. У препроцесорах існує можливість оголошувати та використовувати змінну майже будь-де, враховуючи блоки оголошень, media-запити, або навіть як частину селектору.
$brpoint: 800px;
$s-red: #d33a2c;
$s-things: ".s-text, .cats";
@media screen and (min-width: $brpoint) {
#{$s-things} {
color: $s-red;
}
}
Наведені приклади не будуть працювати, якщо застосовувати користувацькі властивості.
Користувацькі властивості можуть оголошуватися в коді в тих же місцях, що і звичайні властивості CSS. Доречніше розглядати їх не як змінні, а як динамічні властивості. Це означає, що вони можуть застосовуватися тільки всередині блоку оголошення чи, іншими словами, бути «прив'язаними до селектора». Можливе застосування :root
селектора або будь-якого іншого дійсного селектора.
:root { --s-red: #d33a2c; }
@media screen and (min-width: 800px) {
.s-text, .cats {
--margin-left: 1em;
}
}
Існує можливість повернення значення користувацької властивості у будь-якому місці, де б в іншому випадку просто присвоювалось значення. Мова йде про використання користувацької властивості як суцільного значення з операторами скороченої форми або навіть у виразах calc()
.
.s-text, .cats {
color: var(--s-red);
margin: 0 var(--margin-hrz);
padding: calc(var(--margin-hrz) / 2)
}
Однак, вони не можуть застосовуватися у media-запитах або селекторах з :nth-child()
.
Напевно, ви хотіли б дізнатися більше про синтаксис та особливості роботи користувацьких властивостей: роботу з fallback-значеннями, присвоєння одних змінних іншим , але викладеного матеріалу має бути достатньо для розуміння решти концепцій. Додаткову інформацію про особливості функціонування користувацьких властивостей можна знайти тут.
Динамічні vs. Статичні
Окрім видимих відмінностей між користувацькими та препроцесорними змінними, існує більш вагома особливість, що полягає у різних областях видимості. Існує можливість посилатися на змінні як статичні, так і динамічні. Змінні у препроцесорах є статичними, у той же час у користувацьких властивостях — динамічні.
Що стосується CSS, static
— змінні дозволяють змінювати їх значення в різних областях коду на етапі компіляції, але це не призведе до зміни значення в області коду, що передував зміні.
$bg: blue;
.blue {
background: $bg;
}
$bg: red;
.red {
background: $bg;
}
Результат:
.blue {
background: blue;
}
.red {
background: red;
}
Після застосування в CSS змінні зникають. Йдеться про потенціальну можливість визначення змісту .scss
файлу без ознайомлення з HTML, браузером чи іншими вхідними даними. Інша справа із користувацькими властивостями.
Препроцесори мають щось на зразок «видимості блоку», завдяки чому змінні можуть бути тимчасово змінені всередині селектору чи функції.
Значення всередині блоку змінюються, натомість змінні залишаються статичними. Вони пов'язані з блоком, а не з селектором.
У прикладі вище змінна $background
отримала нове значення всередині блоку .example
, але первинне значення за межами блоку залишається незмінним, навіть зважаючи на використання такого ж селектора.
$bg: red;
.example {
$bg: blue;
background: $bg;
}
.example {
background: $bg;
}
Результат:
.example {
background: blue;
}
.example {
background: red;
}
Користувацькі властивості працюють по-різному. Динамічна область видимості у користувацьких властивостей дозволяє бути об'єктом наслідування та каскадування. Властивість пов'язана із селектором, тому якщо її значення змінюється. Це впливає на всі відповідні DOM-елементи так само, як і у випадку з будь-якою іншою CSS-властивістю.
Таким чином, існує можливість змінити значення користувацької властивості всередині media-запиту, використовуючи псевдоселектор (наприклад, hover
) або навіть за допомогою JavaScript.
a {
--lk-color: black;
}
a:hover,
a:focus {
--lk-color: tomato;
}
@media screen and (min-width: 600px) {
a {
--lk-color: blue;
}
}
a {
color: var(--lk-color);
}
Немає потреби змінювати місце застосування користувацької властивості: достатньо змінити її значення в CSS. Тож з однією властивістю можемо мати різні значення у різних місцях чи контекстах сторінки.
Глобальні vs. Локальні
Змінні класифікуються не лише як динамічні та статичні, а і як локальні та глобальні. Ви добре знайомі з цим, якщо працюєте з JavaScript. Можливе застосування змінних як до всього застосунку, так і до окремо виділеної області, що обмежується конкретною функцією чи блоком коду.
В CSS так само. Дещо застосовується глобально, а дещо має більш локальний характер. Фірмові кольори, вертикальні відступи та шрифт найчастіше застосовуються глобально, щоб забезпечити суцільність у веб-сайті чи застосунку. Також маємо справу з локальним застосуванням. Наприклад, компонент button може бути більшим або меншим, в залежності від потреби. Вам не потрібно, щоб однакові розміри button були впроваджені до всієї сторінки.
Ми розробили системи проектування, синтаксичні угоди та JavaScript-біліотеки — усе, щоб допомогти ізолювати локальні компоненти від глобальних елементів дизайну. Користувацькі властивості представляють нові можливості для боротьби з цією проблемою.
Користувацькі CSS-властивості за замовчуванням діють локально у селекторі, що застосовується до них. Виходить щось на зразок локальних змінних. Однак, користувацькі властивості також успадковуються, тому у багатьох ситуаціях вони поводяться як глобальні змінні, особливо у застосуванні до :root
-селектора. Тож необхідно обдумано ставитися до їх використання.
Безліч прикладів демонструють застосування користувацьких властивостей з елементом :root
та, хоч це нормально для демо-версії, в глобальній області це може призвести до безладу та проблем з наслідуванням. На щастя, ці уроки вже засвоєно.
Глобальні змінні, як правило, статичні?
Існує декілька невеликих винятків, але, в загальному, більшість глобальних речей в CSS — статичні.
Глобальні змінні, що визначають брендові кольори, шрифти та відступи, як правило, не змінюються в різних компонентах. Якщо зміни і впроваджуються, то скоріше у якості глобального ребрендингу, що рідко відбувається зі зрілими продуктами. Є сенс застосовувати з цією метою змінні. Вони мають широку область застосування, а також допомагають з узгодженістю. Значення цих змінних не змінюється динамічно.
З цієї причини, я рекомендую використовувати препроцесори для глобальних (статичних) змінних. Перевагою є не тільки гарантія їх однозначної статичності, а й візуальне виокремлення у коді, що робить CSS набагато читабельнішим та зрозумілішим.
Локальні статичні змінні — це добре (іноді)
Зважаючи на однозначну позицію щодо статичності глобальних змінних, можна подумати, що всі локальні змінні повинні бути динамічними. Хоча твердження, що локальні змінні мають тенденцію бути динамічними правдиве, воно не є настільки однозначним, як твердження, що глобальні змінні — статичні.
У багатьох ситуаціях ви цілком можете використовувати локальні статичні змінні. Я використовую препроцесорні змінні в компонентних файлах більше для зручності розробки.
Розглянемо класичний приклад компонента button з різними розмірами.
Мій CSS виглядає приблизно так:
$bt-sml: 1em;
$bt-med: 1.5em;
$bt-lrg: 2em;
.btn {
// візуальні стилі
}
.btn-sml {
font-size: $bt-sml;
}
.btn-med {
font-size: $bt-med;
}
.btn-lrg {
font-size: $bt-lrg;
}
Очевидно, краще було б використовувати змінні кілька разів або отримувати значення margin та padding від size-змінних. Однак, можливість моделювати різні розміри може бути вагомою перевагою.
Зважаючи на те, що більшість статичних змінних глобальні, я розрізняю статичні змінні, що використовуються тільки всередині компонента. Для організації такого способу необхідно додати до змінної префікс, що містить ім'я компонента, або ж обрати інший префікс на зразок c-var-name
для компонента чи l-var-name
для локальної змінної.
Ви можете застосовувати будь-який префікс, а також додавати префікс до глобальних змінних. Незалежно від того, який спосіб ви оберете, розмежування буде корисним при введенні користувацьких властивостей, особливо якщо є необхідність перетворити наявний код.
Коли застосовувати CSS змінні?
Якщо можна використовувати статичні змінні всередині компонентів, коли ж слід використовувати користувацькі властивості?
Перетворення препроцесорних змінних на користувацькі властивості зазвичай не має сенсу, адже їх призначення в іншому. Користувацькі властивості корисні, якщо існують властивості CSS, що змінюються з урахуванням умов у DOM, особливо динамічних, таких як :focus
, :hover
, media-запитів або з урахуванням JavaScript.
Підозрюю, ми завжди будемо використовувати певні форми статичних змінних, хоч, можливо, потребуватимемо цього менше, тому що користувацькі властивості пропонують нові способи організації логіки коду. В багатьох ситуаціях ми будемо працювати з комбінацією змінних препроцесора та користувацьких властивостей.
Корисно знати, що існує можливість присвоєння статичних змінних користувацьким властивостям. Незалежно від того, є вони локальними чи глобальними, подібний метод діє у багатьох ситуаціях, коли необхідно перетворити статичні змінні на локальні динамічні користувацькі властивості.
Зверніть увагу: Чи знали ви, що $var
є допустимим значенням для користувацьких властивостей? Останні версії Sass розпізнають це, тому необхідно інтерполювати змінні, що присвоюються користувацьким властивостям,наприклад #{$var}
. Так Sass дізнається, що ви хочете вивести значення змінної, а не лише $var
у таблиці стилів. Описаний метод застосовується лише при роботі з користувацькими властивостями, коли назви змінних можуть бути також допустимими у CSS.
Якщо звернемося до прикладу з button та вирішимо, що всі кнопки будуть з меншим розміром на мобільних пристроях, то, незалежно від класу в HTML, змінні будуть динамічними. У цьому випадку необхідно застосовувати користувацькі властивості.
$bt-sml: 1em;
$bt-med: 1.5em;
$bt-lrg: 2em;
.btn {
--btn-size: #{$bt-sml};
}
@media screen and (min-width: 600px) {
.btn-med {
--btn-size: #{$bt-med};
}
.btn-lrg {
--btn-size: #{$bt-lrg};
}
}
.btn {
font-size: var(--btn-size);
}
У прикладі я створив єдину користувацьку властивість: --btn-size
. Вона першочергово зображається для всіх елементів button, що належать до класу btn
. Потім я змінив значення --btn-size
для екранів, ширших за 600px, у класах btn-med
та btn-lrg
. Наприкінці я застосував користувацькі властивості для всіх button-елементів в одному місці.
Не ускладнюйте
Динамічна природа користувацьких властивостей дозволяє нам створювати складні компоненти.
З введенням препроцесорів, багато з нас створювали бібліотеки зі складними абстракціями, використовуючи міксини та користувацькі функції. В обмежених випадках, всі ці приклади все ще корисні сьогодні, але майже завжди з використанням статичних змінних. Користувацькі властивості не будуть захищені від подібних експериментів. Але в довгостроковій перспективі, читабельний та зрозумілий код буде мати перевагу над замудреними абстракціями.
Одна з ключових відмінностей між препроцесорами та користувацькими властивостями полягає у тому, що останні працюють під час виконання. Саме тому те, що було прийнятним, з точки зору складності, із препроцесорами, не буде прийнятним із користувацькими властивостями, що добре проілюстровано у прикладі:
:root {
--font-sc: 1.2;
--font-sz-1: calc(var(--font-sc) * var(--font-sz-2));
--font-sz-2: calc(var(--font-sc) * var(--font-sz-3));
--font-sz-3: calc(var(--font-sc) * var(--font-sz-4));
--font-sz-4: 1rem;
}
У прикладі згенеровано шкалу взаємозв'язків — набір числових значень, що співвідносяться за пропорцією. Це часто застосовується у веб-дизайні та розробці для встановлення розміру шрифту та відступів.
Кожна користувацька властивість у прикладі встановлена шляхом множення попереднього значення на пропорцію за допомогою calc()
. Таким чином, отримуємо наступне значення в шкалі.
Пропорції розраховуються в реальному часі, тому, змінивши лише значення --font-sc
, зміниться вся шкала. Наприклад:
@media screen and (min-width: 800px) {
:root {
--font-sc: 1.33;
}
}
Це розумно, лаконічно та набагато швидше, ніж черговий підрахунок всіх значень шкали. Хоч наведений приклад корисний для розробки макету, на продакшені я радше застосую дещо подібне:
:root {
--font-sz1: 1.728rem;
--font-sz2: 1.44rem;
--font-sz3: 1.2em;
--font-sz4: 1em;
}
@media screen and (min-width: 800px) {
:root {
--font-sz1: 2.369rem;
--font-sz2: 1.777rem;
--font-sz3: 1.333rem;
--font-sz4: 1rem;
}
}
Код все ще не ідеальний, тому що порушує згадане правило — глобальні значення повинні бути статичними. Краще було б використовувати препроцесорні змінні та перетворювати їх на локальні динамічні користувацькі властивості, застосовуючи вже описані методи. Важливо також уникати ситуацій переходу від однієї користувацької властивості до іншої.
Змінюйте значення, а не змінну
Пункт є найбільш важливим для ефективного застосування користувацьких властивостей.
У загальному, ви ніколи не повинні змінювати користувацьку властивість, що використовується для якоїсь однієї мети. Нище представлено дві користувацькі властивості, що застосовуються до компонента. Я підставляю значення --font-small
чи --font-large
в залежності від розміру екрана.
:root {
--font-small: 1.2em;
--font-large: 2em;
}
.example {
font-sz: var(--font-small);
}
@media screen and (min-width: 800px) {
.example {
font-sz: var(--font-large);
}
}
Кращим варіантом буде визначити єдину користувацьку властивість, що знаходиться у видимості компонента. Потім, використовуючи media-запит або інший селектор, змінити це значення.
.example {
--exmp-fnt-sz: 1.2em;
}
@media screen and (min-width: 800px) {
.example {
--exmp-fnt-sz: 2em;
}
}
Наприкінці, я використовую значення користувацької властивості в єдиному місці.
.example {
font-sz: var(--exmp-fnt-sz);
}
У цьому та інших прикладах, media-запити використовувалися тільки для зміни значення користувацьких властивостей. Можна також помітити, що var()
застосовувався лише в одному місці.
Я навмисно розмежував оголошення змінної та властивості. На це є багато причин, але переваги очевидні при роботі із адаптивним дизайном.
Адаптивний дизайн з користувацькими властивостями
Труднощі з адаптивним дизайном виникають, коли він в значній мірі покладається на media-запити. Незалежно від того, як ви організовуєте свій CSS, стилі, що відносяться до певного компонента розповсюджуються по всій таблиці.
Буває дуже складно дізнатися яку CSS-властивість буде змінено. Тим не менш, користувацькі властивості CSS можуть допомогти організувати деяку логіку, пов'язану з адаптивним дизайном, та зробити роботу із media-запитами набагато легшою.
Якщо змінюється — це змінна
Властивості, що змінюються за допомогою media-запитів по своїй суті є динамічними, а користувацькі властивості надають засоби для використання динамічних значень в CSS. Насамперед, якщо використовується якийсь media-запит для зміни будь-якої властивості CSS, необхідно помістити це значення у користувацьку властивість. Ви можете перемістити її, разом із media-правилами, hover-ефектами чи будь-якими іншими динамічними селекторами, у верхню частину файлу.
Розділення логіки та дизайну
При правильному розділенні логіки та дизайну, media-запити використовуються тільки для зміни значень користувацьких властивостей. Таким чином вся логіка, що стосується адаптивного дизайну повинна бути у верхній частині файлу, і скрізь, де зустрічається var()
у нашому CSS, ми відразу розуміємо, що ця властивість змінюється. Традиційні методи роботи з CSS не дозволяють дізнатися про одразу.
Багато хто здатен читати та аналізувати CSS одночасно, відстежуючи які властивості змінюються в різних ситуаціях. Тепер в цьому немає потреби! Користувацькі властивості забезпечують зв'язок між логікою та її реалізацією, а це надзвичайно корисно!
Логічне розмежування
Ідея оголошення змінних у верхній частині файлу чи функції не нова. Такий підхід застосовується у багатьох мовах програмування, і в CSS у тому числі. Таким чином створюється візуальне розділення коду у різних частинах документу. Під «логічним розмежуванням» тут розуміється умовне розрізнення секцій. Над умовною лінією знаходяться усі препроцесорні змінні та користувацькі властивості, включно з усіма різними значеннями, що може приймати користувацька властивість. Тож відстежити як змінюється користувацька вдастивість буде набагато легше.
CSS під лінією простий та досить декларативний, тому читабельний. Погляньте на дійсно простий приклад шести колонок на сітці flexbox:
.row {
--row-disp: block;
}
@media screen and (min-width: 600px) {
.row {
--row-disp: flex;
}
}
Користувацька властивість --row-disp
спочатку встановлена як block
. Дисплеї з розширенням більше 600px відображатимуть flex.
Нижче лінії розмежування код виглядатиме подібно:
.row {
display: var(--row-disp);
flex-direction: row;
flex-wrap: nowrap;
}
.col-1, .col-2, .col-3,
.col-4, .col-5, .col-6 {
flex-grow: 0;
flex-shrink: 0;
}
.col-1 { flex-basis: 16.66%; }
.col-2 { flex-basis: 33.33%; }
.col-3 { flex-basis: 50%; }
.col-4 { flex-basis: 66.66%; }
.col-5 { flex-basis: 83.33%; }
.col-6 { flex-basis: 100%; }
Ми одразу розуміємо, що --row-disp
змінюється. Спочатку, --row-disp
набуде значення block
, тому параметри flex будуть ігноруватися.
Наведений приклад досить простий, але якщо розширити його, додавши гнучкі за шириною колонки, що заповнюють пустий простір, то значення flex-grow
,flex-shrink
та flex-basis
буде перетворено на користувацькі властивості. Можете спробувати або розглянути більш детальний приклад тут.
Користувацькі властивості для створення тем
Я виступав проти використання користувацьких властивостей для глобальних динамічних змінних, і мав на увазі, що приєднання користувацьких властивостей до :root
селектору у багатьох випадках шкідливе. Але для кожного правила існує свій виняток, а для користувацьких властивостей — це створення тем.
Використання глобальних користувацьких властивостей може значно полегшити створення тем. Темізація надає можливість користувачам налаштовувати UI, наприклад, змінювати кольори на сторінці профілю. Можливі й більш локалізовані варіанти. Наприклад, існує можливість змінити колір нотаток у Google Keep.
Створення тем, як правило, включає компіляцію окремих таблиць стилів з метою зміни значення за замовчуванням на розсуд користувача або скомпілювати різні стилі для кожного користувача. Обидва способи досить складні і значно впливають на продуктивність.
З користувацькими властивостями відпадає необхідність компілювати різні таблиці стилів; необхідно тільки оновити значення властивості у відповідності з вподобаннями користувача. Зважаючи на те, що властивості успадковуються, зміни можуть застосовуватися до всього застосунку, необхідно лише змінити кореневий елемент.
Глобальні динамічні властивості великими літерами
Користувацькі властивості чутливі до регістру, тому, зважаючи на те, що більшість з них буде локальними, існує сенс застосування заголовних літер при їх оголошенні.
:root {
--THEME-CLR: var(--usr-clr, #d33a2c);
}
Капіталізація змінних часто застосовується до глобальних констант. Для нас це буде символізувати, що властивість вже встановлено у застосунку, і нам не слід змінювати її локально.
Уникайте прямого присвоєння глобальних динамічних властивостей
Користувацькі властивості приймають fallback-значення. Таким чином ми запобігаємо прямому перезапису глобальної користувацької власивості та окремо утримуємо значення користувача. З цією метою застосовуються резервні (fallback) значення.
У прикладі вище присвоюється значення --THEME-CLR
значенню --usr-clr
, у випадку його існування. Якщо ж --usr-clr
не встановлено, буде використано натомість значення #d33a2c. Тобто відпадає необхідність передавати fallback, кожен раз застосовуючи --THEME-CLR
.
У наведеному нижче прикладі можна очікувати, що фон буде встановлено як green
. Однак, значення --usr-clr
не було встановлено для кореневого елементу, тому значення --THEME-CLR
не змінено.
:root {
--THEME-CLR: var(--usr-clr, #d33a2c);
}
body {
--usr-clr: green;
background: var(--THEME-CLR);
}
Непряме встановлення глобальних динамічних властивостей, на зразок наведеного, захищає їх від локального перезапису та гарантує, що налаштування користувача завжди успадкуються від кореневого елементу. Такий метод захистить ваші значення від ненавмисного успадкування.
Якщо ми хочемо, щоб певні властивості успадковувалися, необхідно замінити селектор :root
на *
.
* {
--THEME-CLR: var(--usr-clr, #d33a2c);
}
body {
--usr-clr: green;
background: var(--THEME-CLR);
}
Тепер значення --THEME-CLR
встановлюється для кожного елемента окремо, тому можна використовувати локальне значення --usr-clr
. Іншими словами, колір фону у прикладі буде встановлено як green
.
Оновлюємо користувацькі властивості з JavaScript
Якщо бажаєте встановлювати користувацькі властивості, використовуючи JavaScript, існує досить простий API:
const elm = document.documentElement;
elm.style.setProperty('--USR-CLR', 'tomato');
Тут встановлюється значення --USR-CLR
для documentElement
або, іншими словами, для :root
елементу, який буде успадковуватися всіма іншими елементами.
Однак API не здійснює щось унікальне: існує подібний JavaScript метод для оновлення стилів елемента. Відбувається обробка вбудованих стилів, тому вони будуть більш конкретними, ніж звичайний CSS.
Таким чином, не складно застосувати локальні параметри:
.note {
--nt-color: #eaeaea;
}
.note {
background: var(--nt-color);
}
Тут встановлено значення за замовчуванням для --nt-color
та розповсюджено на компонент .note
. Оголошення змінної розділено з оголошенням властивості навіть у такому простому прикладі.
const elm = document.querySelector('#nt-uid');
elm.style.setProperty('--nt-color', 'yellow');
Далі я сконцентрувався на конкретному випадку .note
елементу та змінив значення користувацької властивості --nt-color
лише для цього елементу. Наразі елемент буде більш конкретним, ніж значення за замовчуванням.
Ви можете переглянути як все буде працювати із використанням React. Користувацькі налаштування можуть бути збережені у локальному сховищі або, у разі об'ємного застосунку, в базі даних.
Управління кольором з користувацькими властивостями
Окрім hex-значень та іменованих кольорів, CSS має функції на зразок rgb()
та hsl()
, що дозволяють встановити окремі параметри кольору, такі як затемнення чи яскравість. Користувацькі властивості можна використовувати у поєднанні з функціями кольору.
:root {
--hue: 25;
}
body {
background: hsl(var(--hue), 80%, 50%);
}
Але деякі широко застосовувані можливості препроцесорів доповнюють функції кольорів, що дозволяє керувати кольором із використанням lighten, darken або desaturate:
darken($bs-color, 10%);
lighten($bs-color, 10%);
desaturate($bs-color, 20%);
Корисним було б застосування наведених можливостей у браузерах. Усе попереду, але поки немає нативних функцій CSS для модифікації кольору, користувацькі властивості можуть заповнити цю прогалину.
Ми бачили, що користувацькі властивості можуть використовуватися в чинних функціях кольору на зразок rgb()
та hsl()
, але також можливе застосування із calc()
. Корисно, якщо необхідно перевести дійсне число у відсотки шляхом множення, наприклад calc(50 * 1%) = 50%
.
:root {
--light: 50;
}
body {
background: hsl(25, 80%, calc(var(--light) * 1%));
}
Причиною нашого бажання зберігати значення light
як дійсне число є можливість маніпулювання із calc
перед перетворенням у відсотки. Наприклад, якщо я хочу затемнити колір на 20%, я можу помножити його яскравість на 0.8. Але це можна зробити набагато легше, якщо виділити розрахунки яскравості в окрему область користувацької властивості.
:root {
--light: 50;
}
body {
--light: calc(var(--light * 0.8));
background: hsl(25, 80%, calc(var(--light) * 1%));
}
Ми могли б навіть абстрагуватися від розрахунків і створити щось на кшталт функцій модифікації кольору в CSS із використанням користувацьких властивостей. Наведений приклад, напевно, досить складний для більшості практичних випадків темізації, але він демонструє потужність динамічних користувацьких властивостей.
Спрощуємо темізацію
Ще однією перевагою використання користувацьких властивостей є можливість спрощення темізації. Застосунку не обов'язково знати як використовуються користувацькі властивості. Натомість, встановленням їх значення керує JavaScript або код на стороні сервера. Таблиці стилів керують яким чином будуть показуватися значення властивостей.
Тож знову відмежовуємо логіку і дизайн. Якщо у вас є команда дизайнерів, вони можуть оновлювати стилі та вирішувати як застосовувати користувацькі властивості, не змінюючи жодного рядка JavaScript чи серверного коду.
Користувацькі властивості також дозволяють перемістити деякі труднощі темізації до CSS, що може мати негативний вплив на розуміння коду, тому намагайтеся не ускладнювати, якщо це можливо.
Користувацькі властивості та їх використання сьогодні
Навіть якщо ви підтримуєте IE10 чи 11, ви можете почати використовувати користувацькі властивості сьогодні. Більшість наведених у статті прикладів демонструють як структурувати СSS, використовуючи користувацькі властивості. З точки зору обслуговування переваги є значними, однак, більшість прикладів лише зменшили те, що могло б бути зроблено із більш складним кодом.
Я використав інструмент postcss-css-variables з метою перетворення більшості можливостей користувацьких властивостей в статичну інтерпретацію такого ж коду. Інший подібний інструмент ігнорує користувацькі властивості у media-запитах або складних селекторах.
Використані інструменти не дозволяють імітувати можливості користувацьких властивостей при виконанні в реальному часі. Тобто ніяких динамічних можливостей темізації чи змінення властивостей з JavaScript. У багатьох ситуаціях це нормально, тому що стандартна тема може бути цілком прийнятною для старіших браузерів.
Завантаження потрібної таблиці стилів
Існує багато способів використання postCSS. Я використовую gulp для компіляції окремих таблиць стилів для нових та старих браузерів. Спрощена версія gulp.task виглядає так:
import gulp from "gulp";
import sass from "gulp-sass";
import postcss from "gulp-postcss";
import rename from "gulp-rename";
import cssvariables from "postcss-css-variables";
import autoprefixer from "autoprefixer";
import cssnano from "cssnano";
gulp.task("css-no-vars", () =>
gulp
.src("./src/css/*.scss")
.pipe(sass().on("error", sass.logError))
.pipe(postcss([cssvariables(), cssnano()]))
.pipe(rename({ extname: ".no-vars.css" }))
.pipe(gulp.dest("./dist/css"))
);
gulp.task("css", () =>
gulp
.src("./src/css/*.scss")
.pipe(sass().on("error", sass.logError))
.pipe(postcss([cssnano()]))
.pipe(rename({ extname: ".css" }))
.pipe(gulp.dest("./dist/css"))
);
Результатом будуть два CSS файли: звичайний з користувацькими властивостями ( styles.css
), а для більш старих браузерів (styles.no-vars.css
). Я хочу, щоб IE10 та 11 обслуговувалися styles.no-vars.css
, а інші браузери — звичайним CSS файлом.
Зазвичай, я виступаю за використання можливостей запитів, натомість IE10 не підтримує їх, тому ми так широко використовували користувацькі властивості. В цьому випадку має сенс використовувати іншу таблицю стилів.
Розумно обробляти іншу таблицю стилів та уникати раптового виникнення елементів без стилю, безумовно, складно. Якщо нема потреби у динамічних можливостях користувацьких властивостей, можна розглянути обслуговування всіма браузерами styles.no-vars.css
, а користувацькі властивості використовувати винятково як інструмент розробки.
Якщо хочете взяти все найкраще від динамічних можливостей користувацьких властивостей, раджу використовувати Критичний CSS. Відповідно до наведеної технології, головна таблиця стилів завантажується асинхронно у той час як критичний CSS вбудовано. Заголовок вашої сторінки буде виглядати приблизно так:
<head>
<style> /* inlined critical CSS */ </style>
<script> loadCSS('non-critical.css'); </script>
</head>
Приклад можна удосконалити, надавши можливість завантажувати styles.css
або styles.no-vars.css
, в залежності від підтримуваних браузером властивостей. Можна визначити таку підтримку:
if ( window.CSS && CSS.supports('color', 'var(--test)') ) {
loadCSS('styles.css');
} else {
loadCSS('styles.no-vars.css');
}
Висновки
Якщо ви з усіх сил намагалися організувати свій CSS ефективно, відчували труднощі з адаптивними компонентами, хотіли організувати темізацію на стороні клієнта або просто впевнено почати використовувати користувацькі властивості, це керівництво дасть усю необхідну інформацію.
Усе зводиться до розуміння різниці між динамічними та статичними змінними в CSS, а також до декількох правил:
- Розділяйте логіку і дизайн;
- Якщо властивість CSS змінюється, зосередьтеся на використанні користувацьких властивостей;
- Змінюйте значення користувацької властивості, а не її саму;
- Глобальні змінні зазвичай статичні.
Якщо керуватися цими узгодженими правилами, використання користувацьких властивостей виявиться набагато легшою справою. Це може навіть повністю перевернути ваше уявлення про CSS.
Ще немає коментарів