Kompromisy CSS-in-JS

Foto: Artem Bali

Nedávno som napísal prehľad na vyššej úrovni CSS-in-JS, hlavne o problémoch, ktoré sa tento prístup pokúša vyriešiť. Autori knižníc zriedka investujú čas do opisovania kompromisov ich riešenia. Niekedy je to preto, že sú príliš neobjektívne a niekedy jednoducho nevedia, ako používatelia používajú tento nástroj. Toto je pokus popísať kompromisy, ktoré som doteraz videl. Myslím si, že je dôležité spomenúť, že som autorom JSS, takže by som sa mal považovať za neobjektívny.

Sociálny dopad

Existuje vrstva ľudí, ktorí pracujú na webovej platforme a nepoznajú žiadny JavaScript. Títo ľudia dostávajú zaplatené za písanie HTML a CSS. CSS-in-JS má obrovský vplyv na workflow vývojárov. Skutočnú transformačnú zmenu nie je možné dosiahnuť bez toho, aby zostali niektorí ľudia pozadu. Neviem, či CSS-in-JS musí byť jediný spôsob, ale hromadné prijatie je jasným znakom problémov s používaním CSS v moderných aplikáciách.

Veľkou časťou problému je naša neschopnosť presne komunikovať prípady použitia, v ktorých CSS-in-JS svieti, a ako ich správne použiť pri úlohe. Veľa nadšencov CSS v JS bolo úspešných v propagácii technológie, ale nie veľa kritikov hovorilo o kompromisoch konštruktívnym spôsobom bez toho, aby sa museli venovať lacným výkyvom v nástrojoch. Výsledkom je, že mnohé kompromisy sme nechali skryté a nevynaložili sme veľké úsilie, aby sme poskytli vysvetlenie a zástupné riešenia.

CSS-in-JS je pokus o ľahšie zvládnutie zložitých prípadov použitia, preto ich netlačte tam, kde to nie je potrebné!

Runtime náklady

Keď sa CSS generuje z JavaScriptu za behu, v prehliadači existuje inherentná réžia. Runtime réžia sa líši v závislosti od knižnice. Toto je dobrá všeobecná referenčná hodnota, ale nezabudnite urobiť vlastné testy. Hlavné rozdiely sa objavia v čase vykonávania v závislosti od potreby úplnej analýzy CSS šablón reťazcov, množstva optimalizácií, podrobností o implementácii dynamických štýlov, nákladov na algoritmy hashovania a integrácie rámcov. *

Okrem potenciálneho režijného zaťaženia musíte zvážiť aj 4 rôzne stratégie viazaného predaja, pretože niektoré knižnice CSS-in-JS podporujú viac stratégií a je na nich, aby ich uplatnil. *

Stratégia 1: Iba generovanie runtime

Generovanie CSS za behu je technika, ktorá v kóde JavaScript vygeneruje reťazec CSS a potom do dokumentu vloží tento reťazec pomocou značky štýlu. Táto technika vytvára šablónu so štýlmi, NIE je inline štýlov.

Kompromisom generovania runtime je neschopnosť poskytnúť štylizovaný obsah v počiatočnom štádiu, keď sa dokument začína načítať. Tento prístup sa zvyčajne hodí pre aplikácie bez obsahu, ktorý môže byť užitočný okamžite. Zvyčajne také aplikácie vyžadujú interakciu používateľa skôr, ako môžu byť pre používateľa skutočne užitočné. Takéto aplikácie často pracujú s obsahom, ktorý je tak dynamický, že sa stane zastaralým hneď po jeho načítaní, takže musíte najskôr vytvoriť aktualizačný kanál, napríklad na Twitteri. Okrem toho, keď je používateľ prihlásený, nie je potrebné poskytovať HTML pre SEO.

Ak interakcia vyžaduje JavaScript, balík sa musí načítať skôr, ako bude aplikácia pripravená. Napríklad môžete zobraziť obsah predvoleného kanála pri načítaní Slacku do dokumentu, je však pravdepodobné, že užívateľ bude chcieť kanál zmeniť hneď potom. Ak ste teda načítali pôvodný obsah, okamžite ich vyhoďte.

Vnímaný výkon takýchto aplikácií sa dá vylepšiť pomocou zástupných symbolov a iných trikov, aby sa aplikácia cítila rýchlejšie ako v skutočnosti je. Také aplikácie sú zvyčajne také veľké, že nebudú užitočné tak rýchlo ako článok.

Stratégia 2: Generovanie runtime s kritickým CSS

Kritický CSS je minimálne množstvo CSS, ktoré sa vyžaduje na úpravu štýlu stránky v pôvodnom stave. Vykresľuje sa pomocou značky štýlu v hlavičke dokumentu. Táto technika je široko používaná s CSS-JS a bez neho. V obidvoch prípadoch je pravdepodobné, že sa pravidlá CSS načítajú dvakrát, a to raz ako súčasť kritického CSS a raz ako súčasť balíka JavaScript alebo CSS. Veľkosť kritického CSS môže byť dosť veľká v závislosti od množstva obsahu. Dokument sa zvyčajne nezachováva v pamäti.

Bez kritického CSS bude musieť statická obsahovo náročná jednostránková aplikácia s runtime CSS-in-JS zobrazovať zástupné symboly namiesto obsahu. Je to zlé, pretože to mohlo byť pre používateľa užitočné oveľa skôr, čím sa zlepšila prístupnosť na zariadeniach nižšej kategórie a na pripojenie s malou šírkou pásma.

Pri kritickom CSS je možné generovať runtime CSS v neskoršej fáze bez blokovania UI v počiatočnej fáze. Upozorňujeme však, že na mobilných zariadeniach nižšej kategórie, ktoré majú približne 5 a viac rokov, môže mať generovanie CSS z jazyka JavaScript negatívny vplyv na výkon. Silne závisí od množstva generovaného CSS a použitej knižnice, takže ju nemožno zovšeobecniť.

Kompromisom tejto stratégie sú náklady na kritickú extrakciu CSS a náklady na generovanie runtime CSS.

Stratégia 3: Iba extrakcia v čase zostavenia

Táto stratégia je predvolená na webe bez CSS-in-JS. Niektoré knižnice CSS-in-JS vám umožňujú extrahovať statický CSS v čase zostavenia. * V tomto prípade sa nevyžaduje žiadna réžia za behu, CSS sa na stránke vykreslí pomocou značky odkazu. Náklady na generovanie CSS sa platia vopred.

Sú tu 2 hlavné kompromisy:

  1. Niektoré dynamické rozhrania API CSS-in-JS nemôžete používať za behu, pretože nemáte prístup k stavu. Vlastné vlastnosti CSS často nemôžete používať, pretože nie sú podporované vo všetkých prehliadačoch a nemôžu byť prirodzene polyfilizované. V takom prípade budete musieť urobiť zástupné riešenia pre dynamické tematické a štátne štýly. *
  2. Bez kritického CSS a s prázdnou vyrovnávacou pamäťou zablokujete prvú farbu, kým sa váš zväzok CSS nenahrá. Odkazový prvok v hlavičke dokumentu blokuje vykreslenie HTML.
  3. Nedeterministická špecifickosť s rozdelením zväzkov na strane v aplikáciách na jednu stránku. *

Stratégia 4: Vytváranie v reálnom čase s kritickým CSS

Táto stratégia tiež nie je jedinečná pre CSS-in-JS. Úplná statická extrakcia s kritickým CSS poskytuje najlepší výkon pri práci s statickejšou aplikáciou. Tento prístup má stále vyššie uvedené kompromisy statického CSS, s tou výnimkou, že značku blokujúceho odkazu je možné presunúť na spodok dokumentu.

Existujú 4 hlavné stratégie vykresľovania CSS. Iba 2 z nich sú špecifické pre CSS-in-JS a žiadna z nich sa nevzťahuje na všetky knižnice.

prístupnosť

CSS-in-JS môže znížiť dostupnosť, ak sa použije nesprávne. To sa stane, keď sa do značnej miery statický obsah implementuje bez extrakcie kritického CSS, takže HTML nebude možné načítať pred načítaním a vyhodnotením balíka JavaScript. K tomu môže dôjsť aj v prípade, že sa obrovský súbor CSS vykreslí pomocou značky blokovacieho odkazu v hlavičke dokumentu, čo je najobľúbenejší súčasný problém s tradičným vkladaním a ktorý nie je špecifický pre CSS-in-JS.

Vývojári musia prevziať zodpovednosť za prístupnosť. Stále existuje silná zavádzajúca myšlienka, že nestabilné pripojenie na internet je problémom ekonomicky slabých krajín. Máme tendenciu zabúdať, že máme problémy s pripojením každý deň, keď vstupujeme do podzemného železničného systému alebo do veľkej budovy. Stabilné bezdrôtové pripojenie bez káblov je mýtus. Stabilné pripojenie Wi-Fi nie je ľahké, napríklad sieť WI-FI 2,4 GHz môže rušiť mikrovlnnú rúru!

Náklady na kritický CSS so serverovým vykreslením

Aby sme získali kritickú extrakciu CSS pre CSS-in-JS, potrebujeme SSR. SSR je proces generovania konečného HTML pre daný stav aplikácie na serveri. V skutočnosti to môže byť dosť zložitý a nákladný proces. Vyžaduje určité množstvo cyklov CPU na serveri pre každú požiadavku HTTP.

CSS-in-JS zvyčajne využíva skutočnosť, že je pripojená k pipeline vykresľovania HTML. * Vie, čo sa vykreslil HTML a čo potrebuje CSS, aby bol schopný vyrobiť jeho absolútne minimálne množstvo. Kritický CSS pridáva ďalšie režijné náklady na vykresľovanie HTML na serveri, pretože tento CSS sa musí tiež kompilovať do konečného reťazca CSS. V niektorých scenároch je však ťažké alebo dokonca nemožné ukladať do vyrovnávacej pamäte na serveri.

Vykreslenie čiernej skrinky

Musíte si byť vedomí toho, ako knižnica CSS-in-JS, ktorú používate, vykresľuje váš CSS. Ľudia napríklad často nevedia, ako štýlové komponenty a emócie implementujú dynamické štýly. Dynamické štýly je syntax, ktorá umožňuje použitie funkcií jazyka JavaScript vo vyhlásení o vašich štýloch. Tieto funkcie prijímajú rekvizity a vracajú blok CSS.

Aby sa zachovala konzistentnosť špecifickosti zdrojového poradia, generujú obe vyššie uvedené knižnice nové pravidlo CSS, ak obsahuje dynamické vyhlásenie a komponent sa aktualizuje novými rekvizitami. Aby som demonštroval, čo tým myslím, vytvoril som toto pieskovisko. V JSS sme sa rozhodli urobiť iný kompromis, čo nám umožňuje aktualizovať dynamické vlastnosti bez generovania nových pravidiel CSS. *

Strmá krivka učenia

Pre ľudí, ktorí sú oboznámení s CSS, ale sú pre JavaScript noví, môže byť počiatočné množstvo práce, ktorá sa má prispôsobiť CSS-in-JS, dosť veľké.

Nemusíte byť profesionálny vývojár JavaScriptu, aby ste mohli písať CSS-in-JS, až do chvíle, keď dôjde k zložitej logike. Nemôžeme zovšeobecniť zložitosť stylingu, pretože to skutočne závisí od prípadu použitia. V prípadoch, keď sa CSS-in-JS stáva zložitejším, je pravdepodobné, že implementácia s vanilkovým CSS by bola ešte zložitejšia.

Pre základné štýly CSS v JS je potrebné vedieť, ako deklarovať premenné, ako používať reťazce šablón a interpolovať hodnoty JavaScriptu. Ak sa používa notácia objektov, je potrebné vedieť, ako pracovať s objektmi JavaScript a syntaxou objektov založenou na knižnici. Ak ide o dynamický štýl, je potrebné vedieť, ako používať funkcie a podmienky jazyka JavaScript.

Celkovo existuje krivka učenia, ktorú nemôžeme poprieť. Táto krivka učenia však zvyčajne nie je o moc väčšia ako učenie Sassu. V skutočnosti som vytvoril tento jednotný kurz, aby som to demonštroval.

Žiadna interoperabilita

Väčšina knižníc libs CSS v JS nie je interoperabilná. To znamená, že štýly napísané pomocou jednej knižnice sa nedajú vykresliť pomocou inej knižnice. Prakticky to znamená, že nemôžete jednoducho prepínať celú svoju aplikáciu z jednej implementácie na druhú. Znamená to tiež, že svoje používateľské rozhranie v systéme NPM nemôžete ľahko zdieľať bez toho, aby ste do zväzku spotrebiteľa vložili vybranú knižnicu CSS-in-JS, pokiaľ nemáte pre svoj CSS statickú extrakciu v čase zostavenia.

Začali sme pracovať na formáte ISTF, ktorý má tento problém vyriešiť, ale bohužiaľ sme ešte nemali čas na jeho uvedenie do stavu pripravenosti na výrobu. *

Domnievam sa, že zdieľanie opakovane použiteľných komponentov agnostických rozhraní používateľského rozhrania vo verejnej doméne je stále ťažko riešiteľný problém.

Bezpečnostné riziká

S CSS-in-JS je možné zaviesť bezpečnostné úniky. Rovnako ako v prípade iných aplikácií na strane klienta musíte pred vykreslením vždy uniknúť vstupu používateľa.

Tento článok vám poskytne podrobnejšie informácie a niektoré zlé príklady.

Nečitateľné názvy tried

Niektorí ľudia si stále myslia, že je dôležité, aby sme na webe uchovávali zmysluplné čitateľné názvy tried. V súčasnosti veľa knižníc CSS-in-JS poskytuje zmysluplné názvy tried na základe názvu deklarácie alebo názvu komponentu vo vývojovom režime. Niektoré z nich dokonca umožňujú prispôsobiť funkciu generátora názvu triedy.

V produkčnom režime však väčšina generuje kratšie názvy pre menšie užitočné zaťaženie. Toto je kompromis, ktorý musí užívateľ knižnice urobiť av prípade potreby prispôsobiť knižnicu.

záver

Existujú kompromisy a pravdepodobne som ich ani nespomenul. Väčšina z nich sa však všeobecne neuplatňuje na všetky CSS-in-JS. Závisia od toho, ktorú knižnicu používate a ako ju používate.

* Na vysvetlenie tejto vety bude potrebný osobitný článok. Dajte mi vedieť na Twitteri (@ oleg008) o tom, ktorý z nich by ste si chceli prečítať viac.