Compromisurile CSS-in-JS

Fotografie de Artem Bali

Recent am scris o imagine de ansamblu la nivel superior a CSS-in-JS, vorbind mai ales despre problemele pe care încearcă să le rezolve această abordare. Autorii bibliotecilor rareori investesc timp în descrierea soluțiilor lor. Uneori, se datorează faptului că sunt prea părtinitoare și uneori nu știu cum utilizează instrumentul. Aici este o încercare de a descrie compromisurile pe care le-am văzut până acum. Cred că este important să menționez că sunt autorul JSS, așa că ar trebui să fiu considerat părtinitor.

Impact social

Există un strat de oameni care lucrează pe platforma web și nu știu niciun JavaScript. Acești oameni sunt plătiți pentru a scrie HTML și CSS. CSS-in-JS a avut un impact uriaș asupra fluxului de lucru al dezvoltatorilor. O schimbare cu adevărat transformatoare nu se poate face niciodată fără ca unii oameni să fie lăsați în urmă. Nu știu dacă CSS-in-JS trebuie să fie singura cale, dar adoptarea în masă este un semn clar al problemelor cu utilizarea CSS în aplicațiile moderne.

O mare parte a problemei este incapacitatea noastră de a comunica cu exactitate cazurile de utilizare în care CSS-in-JS strălucește și cum să-l folosim corect pentru o sarcină. Mulți pasionați de CSS-in-JS au reușit să promoveze tehnologia, dar nu mulți critici au vorbit despre compromisuri într-o manieră constructivă, fără a lua schimbări ieftine la instrumente. Drept urmare, am lăsat multe compromisuri ascunse și nu am depus eforturi puternice pentru a oferi explicații și soluții.

CSS-in-JS este o încercare de a face cazurile de utilizare complexă mai ușor de gestionat, așa că nu o împingeți acolo unde nu este nevoie!

Costul de rulare

Când CSS este generat de la JavaScript la runtime, în browser, există o generație generală inerentă. Runtime overhead variază de la bibliotecă la bibliotecă. Acesta este un reper generic bun, dar asigurați-vă că vă faceți propriile teste. Diferențele majore la timpul de execuție apar în funcție de necesitatea de a avea o analiză CSS completă a șirurilor de șabloane, a cantității de optimizări, a detaliilor de implementare a stilurilor dinamice, a algoritmului hashing și a integrărilor de cadru. *

În afară de potențialul timp de rulare, trebuie să luați în considerare 4 strategii de pachet diferite, deoarece unele biblioteci CSS-in-JS acceptă mai multe strategii și le revine utilizatorului să le aplice. *

Strategia 1: Numai generare de rulare

Generarea CSS Runtime este o tehnică care generează o șir CSS în JavaScript și apoi injectează șirul folosind o etichetă de stil în document. Această tehnică produce o Foaie de stil, NU stiluri inline.

Combaterea generarii de rulare este incapacitatea de a furniza conținut stilat în stadiul incipient, pe măsură ce documentul începe încărcarea. Această abordare se potrivește de obicei pentru aplicații fără conținut care poate fi util imediat. De obicei, astfel de aplicații necesită interacțiuni cu utilizatorii înainte ca acestea să devină cu adevărat utile pentru un utilizator. Adesea, astfel de aplicații funcționează cu un conținut atât de dinamic încât devine învechit imediat ce îl încarci, deci trebuie să stabilești o conductă de actualizare mai devreme, de exemplu, Twitter. În plus, atunci când un utilizator este conectat, nu este necesar să furnizați HTML pentru SEO.

Dacă interacțiunea necesită JavaScript, pachetul trebuie să fie încărcat înainte ca aplicația să fie gata. De exemplu, puteți afișa conținutul unui canal implicit atunci când încărcați Slack în document, dar este probabil ca utilizatorul să vrea să schimbe canalul imediat după aceea. Deci, dacă ați încărcat conținutul inițial doar pentru a le arunca imediat.

Performanțele percepute ale unor astfel de aplicații pot fi îmbunătățite cu ajutorul locurilor de plasare și a altor trucuri pentru a permite aplicației să se simtă mai instantaneu decât este în realitate. Astfel de aplicații sunt de obicei date grele, oricum nu vor fi utile la fel de repede ca articol.

Strategia 2: generarea timpului de rulare cu CSS critic

CSS critic este cantitatea minimă de CSS necesară pentru stilul paginii în starea inițială. Este redat folosind o etichetă de stil din capul documentului. Această tehnică este utilizată pe scară largă cu și fără CSS-in-JS. În ambele cazuri, este posibil să încărcați regulile CSS, o dată ca parte a CSS-ului critic și o dată ca parte a pachetului JavaScript sau CSS. Dimensiunea Critical CSS poate fi destul de mare în funcție de cantitatea de conținut. De obicei, documentul nu va fi pus în cache.

Fără CritS CSS, o aplicație statică cu o pagină unică cu conținut static cu CSS-in-JS de execuție va trebui să arate marcatoare în loc de conținut. Acest lucru este rău, deoarece ar fi putut fi util pentru un utilizator mult mai devreme, îmbunătățind accesibilitatea pe dispozitivele low-end și pentru conexiunile cu lățime de bandă redusă.

Cu CSS critice, generarea CSS în timp de rulare poate fi făcută într-o etapă ulterioară, fără a bloca UI în faza inițială. Atenție, însă, pe dispozitivele mobile low-end, care au o vechime de aproximativ 5 ani, generarea CSS de la JavaScript poate avea un impact negativ asupra performanței. Depinde puternic de cantitatea de CSS generată și de biblioteca folosită, deci nu poate fi generalizată.

Compensarea acestei strategii este costul extragerii CSS critice și costul generarii CSS în timpul rulării.

Strategia 3: extragere în timp exclusiv

Această strategie este cea implicită de pe web fără CSS-in-JS. Unele biblioteci CSS-in-JS vă permit să extrageți CSS statice la momentul de construire. * În acest caz, nu este implicată nicio funcție generală, CSS este redat pe pagină folosind o etichetă de legătură. Costul generației CSS este plătit o dată înainte.

Există 2 compromisuri majore aici:

  1. Nu puteți utiliza unele dintre ofertele dinamice de API-uri CSS-in-JS la timpul de execuție, deoarece nu aveți acces la stat. Adesea, nu puteți utiliza încă proprietăți personalizate CSS, deoarece nu sunt acceptate în fiecare browser și nu pot fi polifilate la ora de construire după natură. În acest caz, va trebui să efectuați soluții de rezolvare pentru tematică dinamică și stil bazat pe stat. *
  2. Fără CSS critic și cu o memorie cache goală, veți bloca prima vopsea până când încărcarea CSS va fi încărcată. Un element de legătură din capul documentului blochează redarea HTMLului.
  3. Specificitate nedeterminantă cu împărțirea pachetelor bazate pe pagini în aplicații cu o singură pagină. *

Strategia 4: Extragerea timpului de construire cu CSS critic

Această strategie nu este unică pentru CSS-in-JS. Extracția statică completă cu CSS critic oferă cele mai bune performanțe atunci când lucrați cu o aplicație mai statică. Această abordare are încă compromisurile menționate mai sus ale unui CSS static, cu excepția faptului că eticheta legăturii de blocare poate fi mutată în partea de jos a documentului.

Există 4 strategii principale de redare CSS. Doar 2 dintre ele sunt specifice CSS-in-JS și niciuna dintre ele nu se aplică tuturor bibliotecilor.

Accesibilitate

CSS-in-JS poate reduce accesibilitatea atunci când este utilizat în mod greșit. Acest lucru se va întâmpla atunci când este implementat un site de conținut în mare măsură static, fără extragerea Critical CSS, astfel încât HTML să nu poată fi pictat înainte de încărcarea și evaluarea pachetului JavaScript. Acest lucru se poate întâmpla și atunci când un fișier CSS uriaș este redat folosind o etichetă de legătură de blocare în capul documentului, care este cea mai populară problemă actuală cu încorporarea tradițională și nu specifică CSS-in-JS.

Dezvoltatorii trebuie să își asume responsabilitatea pentru accesibilitate. Există încă o idee puternică greșită potrivit căreia o conexiune la internet instabilă este o problemă a țărilor slabe din punct de vedere economic. Avem tendința de a uita că avem probleme de conectivitate în fiecare zi când intrăm într-un sistem feroviar subteran sau într-o clădire mare. O conexiune mobilă fără cablu stabilă este un mit. Nu este chiar ușor să ai o conexiune WiFi stabilă, de exemplu, o rețea WI-FI de 2,4 GHz poate obține interferențe de la un cuptor cu microunde!

Costul criticii CSS cu randare din partea serverului

Pentru a obține o extragere critică CSS pentru CSS-in-JS, avem nevoie de SSR. SSR este un proces de generare a HTMLului final pentru o stare dată a unei aplicații pe server. De fapt, poate fi un proces destul de complex și costisitor. Necesită o anumită cantitate de cicluri CPU pe server pentru fiecare solicitare HTTP.

CSS-in-JS folosește de obicei faptul că este conectat la conducta de redare HTML. * Știe ce HTML a fost redat și ce CSS are nevoie, astfel încât să poată produce cantitatea minimă absolută. CSS critic adaugă o suprapunere suplimentară la randarea HTML pe server, deoarece CSS trebuie, de asemenea, compilat într-un șir CSS final. În unele scenarii, totuși, este greu sau chiar imposibil să cachezi pe server.

Cutie neagră de redare

Trebuie să fiți conștienți de modul în care o bibliotecă CSS-in-JS pe care o utilizați vă redă CSS. De exemplu, oamenii nu sunt adesea conștienți de modul în care componentele stilate și emoția pun în aplicare stiluri dinamice. Stilurile dinamice este o sintaxă care permite utilizarea funcțiilor JavaScript în interiorul declarației dvs. de stiluri. Aceste funcții acceptă recuzită și returnează un bloc CSS.

Pentru a menține specificitatea comenzii sursă consecventă, ambele biblioteci numite mai sus generează o nouă regulă CSS dacă conține o declarație dinamică și actualizările componente cu noi elemente de recuzită. Pentru a demonstra ce vreau să spun, am creat această cutie de nisip. În JSS am decis să luăm o tranzacție diferită, ceea ce ne permite să actualizăm proprietățile dinamice fără a genera noi reguli CSS. *

Curba de învățare abruptă

Pentru persoanele care sunt familiarizate cu CSS, dar sunt noi pentru JavaScript, cantitatea inițială de muncă pentru a obține viteza cu CSS-in-JS ar putea fi destul de mare.

Nu trebuie să fiți un dezvoltator JavaScript profesionist pentru a scrie CSS-in-JS, până la implicarea logicii complexe. Nu putem generaliza complexitatea stilului, deoarece depinde într-adevăr de cazul de utilizare. În cazurile în care CSS-in-JS devine complex, este probabil ca implementarea cu CSS vanilată să fie și mai complexă.

Pentru stilul de bază CSS-in-JS, trebuie să știm cum să declarăm variabile, cum să folosim șiruri de șabloane și să interpolăm valorile JavaScript. Dacă se folosește notarea obiectelor, trebuie să știți cum să lucrați cu obiecte JavaScript și sintaxa bazată pe obiecte specifice bibliotecii. Dacă este implicat un stil dinamic, trebuie să știți cum să utilizați funcțiile și condiționările JavaScript.

În general, există o curbă de învățare, nu o putem nega. Această curbă de învățare nu este de obicei mult mai mare decât învățarea lui Sass. De fapt, am creat acest curs de capete de ou pentru a demonstra acest lucru.

Fără interoperabilitate

Majoritatea libs CSS-in-JS nu sunt interoperabile. Aceasta înseamnă că stilurile scrise folosind o bibliotecă nu pot fi redate folosind o altă bibliotecă. Practic înseamnă că nu puteți schimba întreaga aplicație cu ușurință de la o implementare la alta. Înseamnă, de asemenea, că nu puteți partaja cu ușurință interfața de utilizator pe NPM fără a aduce biblioteca CSS-in-JS aleasă în pachetul consumatorului, cu excepția cazului în care aveți o extracție statică integrată pentru CSS.

Am început să lucrăm la formatul ISTF care ar trebui să rezolve această problemă, dar, din păcate, nu am avut încă timp să ajungem într-o stare pregătită pentru producție. *

Consider că partajarea componentelor UI de tip agnostic cadru reutilizabile în domeniul public este încă o problemă în general greu de rezolvat.

Riscuri de securitate

Este posibil să introduceți scurgeri de securitate cu CSS-in-JS. La fel ca în cazul oricărei aplicații din partea clientului, trebuie să evadați intrarea utilizatorului înainte de a o face, întotdeauna.

Acest articol vă va oferi mai multe informații și câteva exemple defăcătoare.

Nume de lectură care nu pot fi citite

Unii oameni încă consideră că este important să păstrăm pe web nume de clasă care să poată fi citite cu semnificație. În prezent, multe biblioteci CSS-in-JS furnizează nume de clasă semnificative bazate pe numele declarației sau pe numele componentei în modul de dezvoltare. Unele dintre ele vă permit chiar să personalizați funcția de generator de nume de clasă.

În modul de producție, totuși, majoritatea generează nume mai scurte pentru o sarcină utilă mai mică. Acesta este un compromis pe care utilizatorul bibliotecii trebuie să-l creeze și să-l personalizeze, dacă este nevoie.

Concluzie

Există compromisuri și probabil că nici nu le-am menționat pe toate. Dar majoritatea nu se aplică în mod universal tuturor CSS-in-JS. Depind de ce bibliotecă folosești și de cum o folosești.

* Va fi nevoie de un articol dedicat pentru a explica această propoziție. Anunță-mă pe Twitter (@ oleg008) despre care ai vrea să citești mai multe.