Промените на 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. Размерът на Critical CSS може да бъде доста голям в зависимост от количеството съдържание. Обикновено документът няма да се кешира.

Без критичен CSS, статично приложение, съдържащо много страници с една страница, с време на изпълнение CSS в JS, ще трябва да показва заместители вместо съдържание. Това е лошо, защото може да е полезно за потребителя много по-рано, подобрявайки достъпността на устройства от нисък клас и за връзки с ниска честотна лента.

С критичен CSS, създаването на CSS по време на изпълнение може да се извърши на по-късен етап, без да се блокира потребителският интерфейс в началната фаза. Внимавайте обаче на мобилни устройства от нисък клас, които са на около 5+ години, CSS генерирането от JavaScript може да има отрицателно въздействие върху производителността. Силно зависи от количеството на генерирания CSS и използваната библиотека, така че не може да бъде генерализиран.

Компромисът на тази стратегия е цената на извличането на критични CSS и разходите за генериране на CSS по време на изпълнение.

Стратегия 3: Само извличане на време за изграждане

Тази стратегия е тази по подразбиране в мрежата без CSS-in-JS. Някои библиотеки CSS в JS ви позволяват да извличате статичен CSS по време на изграждане. * В този случай не се включва режийни режими на изпълнение, CSS се изобразява на страницата с помощта на маркер за връзка. Цената на генерацията на CSS се плаща веднъж предварително.

Тук има 2 основни компромиси:

  1. Не можете да използвате някои от динамичните 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.

Разработчиците трябва да поемат отговорност за достъпността. Все още съществува силна погрешна идея, че нестабилната интернет връзка е проблем на икономически слабите страни. Склонни сме да забравяме, че имаме проблеми със свързаността всеки ден, когато влизаме в подземна железопътна система или голяма сграда. Стабилната мобилна връзка без кабел е мит. Дори не е лесно да имате стабилна WiFi връзка, например, 2.4 GHz WI-FI мрежа може да получи смущения от микровълнова фурна!

Цената на критичния CSS с изобразяване от страна на сървъра

За да получим критично CSS извличане за CSS в JS, се нуждаем от SSR. SSR е процес на генериране на крайния HTML за дадено състояние на приложение на сървъра. Всъщност това може да бъде доста сложен и скъп процес. Изисква определено количество CPU цикли на сървъра за всяка 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-in-JS, до момента, в който сложната логика се включва. Не можем да обобщим сложността на стилистиката, тъй като тя наистина зависи от случая на употреба. В случаите, когато CSS-in-JS стане сложен, вероятно е прилагането с ванилов CSS да е още по-сложно.

За основни CSS-в-JS стилистика трябва да знаете как да декларирате променливи, как да използвате низове на шаблон и интерполирате стойностите на JavaScript. Ако се използва обект-нотация, човек трябва да знае как да работи с JavaScript обекти и специфичния за библиотеката обект-базиран синтаксис. Ако става въпрос за динамичен стайлинг, човек трябва да знае как да използва функциите и условията на JavaScript.

Като цяло има крива на обучение, не можем да я отречем. Тази крива на обучение обикновено не е много по-голяма от изучаването на Сас. Всъщност аз създадох този курс за патладжани, за да демонстрирам това.

Няма оперативна съвместимост

Повечето CSS в JS libs не са оперативно съвместими. Това означава, че стилове, написани с помощта на една библиотека, не могат да бъдат изобразявани с помощта на друга библиотека. На практика това означава, че не можете лесно да превключвате цялото си приложение от една към друга реализация. Това също означава, че не можете лесно да споделите потребителския си интерфейс на NPM, без да внесете вашата CSS-в-JS библиотека по избор в пакета на потребителите, освен ако нямате статично извличане на време за изграждане на вашия CSS.

Започнахме да работим по ISTF формат, който трябва да отстрани този проблем, но за съжаление все още не сме имали време да го върнем в състояние, готово за производство. *

Мисля, че споделянето на рамкови компоненти за агностичен интерфейс с многократна употреба в публичното пространство все още е трудно разрешим проблем.

Рискове за сигурността

Възможно е да се въведат течове за сигурност с CSS-in-JS. Както при всички клиентски приложения, винаги трябва да избягвате потребителското въвеждане, преди да го направите.

Тази статия ще ви даде по-голяма представа и някои примамливи примери.

Непрочетени имена на класове

Някои хора все още смятат, че е важно да поддържаме значими четими имена на класове в интернет. Понастоящем много CSS в JS библиотеки предоставят смислени имена на класове въз основа на името на декларация или име на компонент в режим на разработка. Някои от тях дори ви позволяват да персонализирате функцията на генератора на име на клас.

В производствен режим обаче повечето от тях генерират по-кратки имена за по-малък полезен товар. Това е компромис, който потребителят на библиотеката трябва да направи и персонализира, ако е необходимо.

заключение

Компромиси има и вероятно дори не ги споменах. Но повечето от тях не се прилагат универсално за всички CSS-in-JS. Те зависят от това коя библиотека използвате и как я използвате.

* Ще е необходима специална статия, за да обясни това изречение. Кажете ми в Twitter (@ oleg008) за това кой от тях бихте искали да прочетете повече.