Компроміси CSS-in-JS

Фото Артема Балі

Нещодавно я написав огляд CSS-in-JS вищого рівня, переважно розповідаючи про проблеми, які цей підхід намагається вирішити. Автори бібліотеки рідко вкладають час на опис компромісів свого рішення. Іноді це тому, що вони занадто упереджені, а іноді просто не знають, як користувачі застосовують цей інструмент. Отже, це спроба описати компроміси, які я бачив досі. Я думаю, що важливо згадати, що я є автором JSS, тому мене слід вважати упередженим.

Соціальний вплив

Є шар людей, які працюють на веб-платформі і не знають JavaScript. Цим людям платять за написання HTML та CSS. CSS-in-JS зробив величезний вплив на робочий процес розробників. По-справжньому трансформативні зміни ніколи не можуть бути здійснені, якщо деякі люди не залишаться позаду. Я не знаю, чи повинен CSS-in-JS бути єдиним способом, але масове прийняття - це явна ознака проблем із використанням CSS у сучасних додатках.

Велика частина проблеми полягає в нашій нездатності точно повідомляти випадки використання, коли CSS-in-JS світить, і як правильно його використовувати для виконання завдання. Багато ентузіастів CSS-JS досягли успіху в просуванні технологій, але не багато критиків говорили про компроміси в конструктивному плані, не беручи дешевих змін на інструменти. Як наслідок, ми залишили багато викриттів прихованими і не доклали великих зусиль, щоб надати пояснення та шляхи вирішення.

CSS-in-JS - це спроба спростити обробку складних справ, тому не натискайте її там, де це не потрібно!

Вартість виконання

Коли CSS генерується з JavaScript під час виконання, у браузері є властиві накладні витрати. Час виконання триває від бібліотеки до бібліотеки. Це хороший загальний орієнтир, але обов'язково робіть власні тести. Основні відмінності під час виконання з'являються залежно від необхідності повного розбору CSS-рядків шаблонів, кількості оптимізацій, деталей реалізації динамічних стилів, алгоритму хешування та вартості інтеграції рамок. *

Окрім можливих накладних витрат на виконання, вам потрібно розглянути 4 різні стратегії поєднання, оскільки деякі бібліотеки CSS в JS підтримують декілька стратегій, і користувач повинен їх застосувати. *

Стратегія 1: Тільки генерація часу виконання

Генерація CSS під час виконання - це техніка, яка генерує CSS-рядок у JavaScript, а потім вводить цей рядок, використовуючи тег стилю в документ. Ця методика створює таблицю стилів, а не вбудовані стилі.

Компроміс генерації виконання - це неможливість надання стильового вмісту на початковій стадії, коли документ починає завантажуватися. Цей підхід зазвичай підходить для програм без вмісту, який може бути корисний негайно. Зазвичай такі програми вимагають взаємодії з користувачем, перш ніж вони дійсно можуть стати корисними для користувача. Часто такі програми працюють із настільки динамічним вмістом, що він застаріває, як тільки ви завантажуєте його, тому вам потрібно налагодити конвеєр оновлення на початку, наприклад, Twitter. Крім того, коли користувач увійшов у систему, немає необхідності вводити HTML для SEO.

Якщо для взаємодії потрібен JavaScript, пакет потрібно завантажити, перш ніж програма буде готова. Наприклад, ви можете показати вміст каналу за замовчуванням під час завантаження Slack в документі, але, ймовірно, користувач захоче змінити канал відразу після цього. Тож якщо ви завантажили початковий вміст, щоб негайно їх викинути.

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

Стратегія 2: Генерування часу роботи з критичним CSS

Критичний CSS - це мінімальна кількість CSS, необхідна для стилювання сторінки у початковому стані. Він відображається за допомогою тегу стилю в заголовку документа. Ця методика широко використовується з і без CSS-в-JS. В обох випадках ви, ймовірно, подвійно завантажите правила CSS, один раз як частина критичного CSS та один раз як частина пакета JavaScript або CSS. Розмір критичного CSS може бути досить великим залежно від кількості вмісту. Зазвичай документ не буде кешований.

Без критичного CSS статичне додаток на одній сторінці, що містить важкий вміст, із програмою CSS-in-JS, повинен буде показувати заповнювачі замість вмісту. Це погано, оскільки воно могло бути корисним користувачеві набагато раніше, покращуючи доступність пристроїв низького класу та для низькосмугових з'єднань.

За допомогою критичного CSS створення циклу виконання CSS може бути виконано на більш пізньому етапі, не блокуючи інтерфейс користувача на початковій фазі. Будьте попереджені, але на мобільних пристроях низького класу, яким приблизно 5+ років, покоління CSS з JavaScript може мати негативний вплив на продуктивність. Це сильно залежить від кількості CSS, що генерується, та використовуваної бібліотеки, тому її неможливо узагальнити.

Компроміс цієї стратегії - це вартість видобутку критичного CSS та вартість генерації CSS під час виконання.

Стратегія 3: Лише видобуток часу

Ця стратегія є типовою в Інтернеті без CSS-в-JS. Деякі бібліотеки CSS в JS дозволяють витягувати статичний CSS під час збирання. * У цьому випадку жодних накладних витрат часу не задіяно, CSS відображається на сторінці за допомогою тегу посилання. Вартість генерації CSS оплачується один раз достроково.

Тут є дві основні компроміси:

  1. Ви не можете використовувати деякі динамічні API-програми API CSS-in-JS під час виконання, оскільки у вас немає доступу до держави. Часто ви все ще не можете користуватися спеціальними властивостями CSS, оскільки вони підтримуються не в кожному браузері і не можуть бути заповнені поліфазовами під час створення. У цьому випадку вам доведеться зробити обхідні шляхи для динамічної тематизації та стилів на основі штату. *
  2. Без критичного CSS і з порожнім кешем ви заблокуєте першу фарбу, поки ваш пакет CSS не завантажиться. Елемент посилання в заголовку документа блокує візуалізацію HTML.
  3. Недетерміновані специфіки з розділенням на основі сторінок розбиття пакетів в додатках на одній сторінці. *

Стратегія 4: Видобуток часу складання за допомогою критичного CSS

Ця стратегія також не властива тільки CSS-in-JS. Повний статичний витяг з критичним CSS забезпечує найкращі показники роботи при більш статичному застосуванні. Цей підхід все ще має вищезгадані компроміси статичного CSS, за винятком того, що тег блокуючої посилання може бути переміщений до нижньої частини документа.

Існує 4 основні стратегії візуалізації CSS. Лише 2 з них характерні для CSS-in-JS, і жодна з них не стосується всіх бібліотек.

Доступність

CSS-in-JS може зменшити доступність при неправильному використанні. Це станеться, коли сайт з великим статичним вмістом буде реалізований без критичного вилучення CSS, так що HTML не можна буде малювати до завантаження та оцінки пакета JavaScript. Це також може статися, коли величезний CSS-файл виводиться за допомогою тега, що блокує посилання в голові документа, що є найпопулярнішою поточною проблемою з традиційним вбудовою і не характерною для CSS-в-JS.

Розробники повинні брати на себе відповідальність за доступність. Досі існує сильна помилкова думка про те, що нестабільне підключення до Інтернету є проблемою економічно слабких країн. Ми, як правило, забуваємо, що у нас виникають проблеми з підключенням кожного дня, коли ми заходимо в підземну залізничну систему чи велику будівлю. Міф про стабільне без кабельного зв'язку - це міф. Зробити стабільне бездротове з'єднання навіть непросто, наприклад, мережа WI-FI 2,4 ГГц може отримати перешкоди від мікрохвильової печі!

Вартість критичного CSS з візуалізацією на стороні сервера

Щоб отримати критичне вилучення CSS для CSS-in-JS, нам потрібен SSR. SSR - це процес генерації кінцевого HTML для заданого стану програми на сервері. Насправді це може бути досить складний і дорогий процес. Для кожного запиту HTTP потрібна певна кількість циклів процесора на сервері.

CSS-in-JS зазвичай використовує той факт, що він підключений до конвеєра HTML-рендерінгу. * Він знає, який HTML був наданий і який CSS йому потрібен, щоб він міг генерувати абсолютну мінімальну кількість його. Критичний CSS додає додаткових накладних витрат на візуалізацію HTML на сервері, тому що CSS також потрібно компілювати в остаточний рядок CSS. У деяких сценаріях кеш на сервері важко або навіть неможливо.

Подання чорного поля

Вам потрібно знати, як бібліотека CSS-в-JS, яку ви використовуєте, надає ваш CSS. Наприклад, люди часто не знають, як Styled Components та Emotion реалізують динамічні стилі. Динамічні стилі - це синтаксис, який дозволяє використовувати функції JavaScript всередині оголошення ваших стилів. Ці функції приймають реквізити та повертають блок CSS.

Щоб зберегти специфіку порядку джерела, обидві вищеназвані бібліотеки генерують нове правило CSS, якщо воно містить динамічне оголошення та оновлення компонента новими реквізитами. Щоб продемонструвати, що я маю на увазі, я створив цю пісочницю. У JSS ми вирішили здійснити інший компроміс, який дозволяє нам оновлювати динамічні властивості без генерування нових правил CSS. *

Крута крива навчання

Для людей, які знайомі з CSS, але які не знайомі з JavaScript, початковий обсяг роботи над швидкістю роботи з CSS в JS може бути досить великим.

Вам не потрібно бути професійним розробником JavaScript, щоб писати CSS-в-JS, до тих пір, поки не вплутується складна логіка. Ми не можемо узагальнити складність стилів, оскільки це дійсно залежить від випадку використання. У випадках, коли CSS-in-JS стає складним, цілком ймовірно, що реалізація з ванільним CSS буде ще складнішою.

Для базового стилю CSS-в-JS потрібно знати, як оголошувати змінні, як використовувати рядки шаблону та інтерполювати значення JavaScript. Якщо використовується нотація об'єкта, потрібно знати, як працювати з об’єктами JavaScript та синтаксисом, що базується на об'єкті. Якщо задіяний динамічний стиль, потрібно знати, як користуватися функціями та умовами JavaScript.

Загалом крива навчання є, ми не можемо заперечувати це. Ця крива навчання, як правило, не набагато більша, ніж вивчення Сасса. Насправді я створив цей курс яєчного голови, щоб продемонструвати це.

Немає сумісності

Більшість ліфтів CSS в JS не є сумісними. Це означає, що стилі, написані за допомогою однієї бібліотеки, не можуть бути відображені за допомогою іншої бібліотеки. Це практично означає, що ви не можете легко переключити всю програму з однієї реалізації на іншу. Це також означає, що ви не можете легко поділитись своїм інтерфейсом користувача на NPM, не ввівши вибрану бібліотеку CSS в комплект споживача, якщо у вас не буде статичного вилучення для CSS вбудованого часу.

Ми почали працювати над форматом ISTF, який повинен вирішити цю проблему, але, на жаль, ми ще не встигли довести її до стану, готового до виробництва. *

Я думаю, що обмін компонентами загального користувальницького інтерфейсу для багаторазового використання в загальнодоступному просторі все ще є важко вирішуваною проблемою.

Ризики безпеки

Можливо ввести витоки безпеки за допомогою CSS-in-JS. Як і будь-які додатки на стороні клієнта, вам потрібно завжди уникати введення даних користувача перед його наданням.

Ця стаття дасть вам більше розуміння та приклад привабливих прикладів.

Нечитабельні назви класів

Деякі люди все ще вважають, що важливо, щоб ми зберігали в Інтернеті значущі читані імена класів. В даний час багато бібліотеки CSS в JS надають змістовні імена класів на основі імені декларації або імені компонента в режимі розробки. Деякі з них навіть дозволяють налаштувати функцію генератора імен класу.

Однак у виробничому режимі більшість із них генерують короткі назви для меншої корисної навантаження. Це компроміс, який користувач бібліотеки повинен зробити та налаштувати, якщо це необхідно.

Висновок

Компроміси існують, і я, мабуть, навіть не згадував про них. Але більшість із них не застосовуються універсально до всіх CSS-в-JS. Вони залежать від того, яку бібліотеку ви використовуєте та як нею користуєтесь.

* Для пояснення цього речення знадобиться спеціальна стаття. Повідомте мене у Twitter (@ oleg008) про те, про який ви хочете прочитати більше.