Scris de Harry Roberts pe vrăjitorie CSS.

Acesta este primul dintr-un post în două părți. Citiți partea 2.

Recomandările de performanță de câțiva ani în urmă au afirmat pur și simplu că ar trebui „să reducem numărul de cereri pe care le facem”. În timp ce acesta este, în general, un sfat perfect solid, nu este lipsit de avertismente. De fapt, putem face paginile să se încarce mult mai repede prin distribuirea elegantă a activelor noastre pe câteva cereri mai bine luate în considerare, mai degrabă decât mai puține.

Una dintre „cele mai bune practici” susținute, născută din acest sfat, a fost adoptarea codificării Base64: actul de a prelua un activ extern (de exemplu, o imagine) și de a-l încorpora direct în resursa text care l-ar folosi (de exemplu, o foaie de stil). Rezultatul este că reducem numărul de solicitări HTTP și că ambele materiale (de exemplu, foaia de stil și imaginea) ajung în același timp. Sună ca un vis, corect?

Din păcate, activele de codificare Base64 sunt foarte mult un anti-model 1. În acest articol, sper să vă împărtășesc câteva informații despre optimizarea căilor critice, Gzip și, bineînțeles, Base64.

Să ne uităm la un cod

Motivul pentru care am fost motivat să scriu acest articol este pentru că tocmai am făcut un audit de performanță pentru un client și am dat peste problemele pe care urmează să le subliniez. Aceasta este o foaie de stil reală de la un client real: lucrurile sunt anonimizate, dar acesta este un proiect complet real.

Am rulat un profil rapid de rețea peste pagină și am descoperit o singură foaie de stil (ceea ce este cam bun într-un fel, deoarece cu siguranță nu vrem să vedem 12 solicitări de foaie de stil), dar foaia de stil a intrat în mare 925K după ce a fost decomprimat și extins. Cantitatea reală de octeți care vin peste fir a fost substanțial mai mică, dar totuși foarte mare la 232K.

De îndată ce începem să vedem foi de stil de acea dimensiune, ar trebui să începem să intrăm în panică. Eram relativ sigur - fără să trebuiască măcar să mă uit - că va exista ceva Base64 aici. Asta nu înseamnă că m-am așteptat să fie singurul factor (pluginurile, lipsa arhitecturii, moștenirea etc. sunt susceptibile să joace un rol), dar foile de stil atât de mari sunt de obicei indicative pentru Base64. Încă:

  1. Base64 sau nu, 925K de CSS este terifiant.
  2. Reducerea acestuia se reduce doar la 759K.
  3. Gzipping ne duce la doar 232K. Exact același cod comprimat cu 693K.
  4. 232K peste fir este încă terifiant.

Este nevoie de un efect de uimire de 88 ms chiar pentru a analiza o foaie de stil de acea dimensiune. Obținerea acestuia prin rețea este doar începutul problemelor noastre:

base64

Am pregătit fișierul 2, l-am salvat pe mașina mea, l-am rulat prin CSSO, apoi am rulat acea ieșire minimizată prin Gzip pe setarea sa obișnuită. Așa am ajuns la aceste numere și am rămas uitându-mă la asta:

Următorul lucru de făcut a fost să vedem cât de mulți dintre acești octeți provin din activele codificate Base64. Pentru a rezolva acest lucru, am eliminat pur și simplu (și destul de grosolan) toate liniile/declarațiile care conțineau date: șiruri (: g/data:/d 3 pentru utilizatorii Vim care citesc acest lucru). Majoritatea acestei codificări Base64 a fost pentru imagini/sprite și câteva fonturi. Am salvat apoi acest fișier ca no-base64.css și am rulat aceeași minificare și Gzipping peste asta:

În CSS-ul nostru necomprimat, am reușit să pierdem un întreg 217K din Base64. Acest lucru ne lasă încă cu o cantitate alarmantă de CSS (708K este destul de dificil), dar am reușit să scăpăm de un bun 23,45% din codul nostru.

Unde lucrurile devin cu adevărat surprinzătoare acum, este după ce am Gzipped ce a mai rămas. Am reușit să trecem de la 708K până la doar 68K peste fir! Asta este o economie de 90,39%. Wow.

Salvează Gzip ...

Gzip este incredibil! Este probabil cel mai bun instrument unic pentru protejarea utilizatorilor de dezvoltatori. Am reușit să economisim 90% peste fir doar prin comprimarea CSS-ului nostru. De la 708K până la 68K gratuit.

... Uneori

Cu toate acestea, Gzip lucrează versiunea codificată non-Base64. Dacă ne uităm la CSS original (CSS cu codare Base64), vom constata că am făcut doar o economie de 74,91%.

Base64? Dimensiune brută economisire dimensiune comprimată
da 925K 232K 74,91%
Nu 708K 68K 90,39%

Diferența dintre cele două opțiuni este de 164K (70,68%). Putem trimite cu 164K CSS mai puțin prin cablu doar mutând acele active în alt loc mai potrivit.

Base64 se comprimă teribil. Data viitoare când cineva încearcă să meargă, da, dar Gzip ... scuză-te, spune-le despre asta (dacă încearcă să justifice Base64, adică).

Deci, de ce este atât de rău Base64?

Bine, deci suntem destul de clari acum că Base64 crește dimensiunea fișierelor într-un mod în care Gzip nu ne poate ajuta cu adevărat, dar aceasta este doar o mică parte a problemei. De ce ne este atât de frică de această creștere a dimensiunii fișierelor? O singură imagine ar putea cântări mult peste 232K, deci nu este mai bine să începem de acolo?

Întrebare bună și mă bucur că ai menționat imagini ...

Trebuie să vorbim despre imagini

Pentru a înțelege cât de rău este Base64, trebuie mai întâi să înțelegem cât de bune sunt imaginile. Opinie controversată: imaginile nu sunt la fel de rele pentru performanță pe cât crezi.

Da, imaginile sunt o problemă. De fapt, acestea contribuie numărul unu la umflarea paginii. Începând cu 2 decembrie 2016, imaginile reprezintă aproximativ 1623K (sau 65,46%) din media paginii web. Asta face ca foaia noastră de stil de 232K să pară o picătură în ocean prin comparație. Cu toate acestea, există diferențe fundamentale între modul în care browserele tratează imaginile și foile de stil:

Imaginile nu blochează redarea; foile de stil.

Un browser va începe să redea o pagină, indiferent dacă imaginile au sosit sau nu. Heck, un browser va reda o pagină chiar dacă imaginile nu ajung niciodată! Imaginile nu sunt resurse critice, așa că, deși reprezintă o cantitate excesivă de octeți peste fir, nu reprezintă un blocaj.

CSS, pe de altă parte, este o resursă critică. Browserele nu pot începe redarea unei pagini până nu au construit arborele de redare. Browserele nu pot construi arborele de redare până nu au construit CSSOM. Nu pot construi CSSOM până când nu au sosit toate foile de stil, nu au fost necomprimate și analizate. CSS este un blocaj.

Sperăm că acum puteți vedea de ce ne este atât de frică de octeții CSS: acestea servesc doar pentru a întârzia redarea paginii și îl lasă pe utilizator să se uite la un ecran gol. Sperăm că ați realizat și ironia dureroasă a codificării imaginilor Base64 în fișierele dvs. CSS: tocmai ai transformat sute de kilobyți de resurse care nu blochează în resurse blocante în căutarea performanței. Toate aceste imagini ar fi putut să-și croiască drum prin rețea ori de câte ori erau gata, dar acum au fost forțați să se prezinte alături de resurse critice mult mai ușoare. Și asta nu înseamnă că imaginile ajung mai devreme; înseamnă că CSS-ul critic ajunge mai târziu. Ar putea chiar să se înrăutățească?!

Browserele sunt inteligente. Chiar inteligent. Ele fac o mulțime de optimizări de performanță pentru noi, deoarece - cel mai adesea - știu mai bine. Să ne gândim la sensibilitate:

Am oferit browserului trei imagini potențiale de utilizat aici, dar va descărca doar una dintre ele. Funcționează de care are nevoie, o aduce pe aceasta și le lasă pe celelalte două neatinse.

De îndată ce am bazat aceste imagini, octeții pentru toți trei sunt descărcați, triplând efectiv (sau în jur) cheltuielile noastre generale. Iată o bucată reală de CSS din acest proiect (am eliminat datele codificate din motive evidente, dar în totalitate acest fragment de cod totaliza 26K înainte de Gzip; 18K după):

Toți utilizatorii, indiferent dacă sunt sau nu pe dispozitive retina (heck, chiar și utilizatorii cu browsere care nici măcar nu acceptă interogări media), vor fi obligați să descarce acel 18K suplimentar de CSS înainte ca browserul lor să înceapă chiar să pună o pagină împreună.

Elementele codificate Base64 vor fi întotdeauna descărcate, chiar dacă nu sunt utilizate niciodată. Acest lucru este risipitor în cel mai bun caz, dar atunci când consideri că deșeurile blochează de fapt redarea, este și mai rău.

Și trebuie să vorbim despre fonturi

Am menționat doar imagini până acum, dar fonturile sunt aproape exact aceleași, cu excepția unor nuanțe în legătură cu modul în care browserele gestionează blițul textului nestilat/invizibil (FOUT sau FOIT). Fonturile din acest proiect totalizează 166K de CSS necomprimat (124K Gzipped (există din nou acea delta de compresie îngrozitoare)).

Fără a desconecta articolul prea mult, fonturile sunt, de asemenea, elemente care nu trăiesc în mod natural pe calea ta critică, ceea ce este o veste minunată: pagina ta poate reda fără ele. Cu toate acestea, problema este că browserele gestionează fonturile web diferit:

  • Chrome și Firefox nu afișează deloc text timp de până la 3 secunde. Dacă fontul web ajunge în aceste trei secunde, textul trece de la invizibil la fontul personalizat. Dacă fontul încă nu a sosit după 3 secunde, textul se schimbă de la invizibil la orice alternativă pe care ați definit-o. Acesta este FOIT.
  • IE afișează imediat fontul alternativ și apoi îl schimbați pentru fontul personalizat de îndată ce ajunge. Acesta este FOUT. Aceasta este, după părerea mea, cea mai elegantă soluție.
  • Safari arată text invizibil până ajunge fontul. Dacă fontul nu ajunge niciodată, nu arată niciodată o rezervă. Acesta este FOIT. Este, de asemenea, o urâciune absolută. Există toate șansele ca utilizatorii dvs. să nu poată vedea niciodată text pe pagina dvs.

Pentru a evita acest lucru, oamenii au început Base64 să-și integreze fonturile în foile de stil: dacă CSS și fonturile ajung exact în același timp, atunci nu ar exista FOIT sau FOUT, deoarece construcția CSSOM și livrarea fontului se întâmplă la mai mult sau mai puțin în același timp.

Doar, ca și până acum, mutarea fonturilor pe calea critică nu accelerează livrarea acestora, ci doar întârzie CSS-ul. Există câteva soluții destul de inteligente de încărcare a fonturilor, dar Base64 nu este una dintre ele.

Și trebuie să vorbim despre cache

Base64 ne afectează și capacitatea de a avea strategii de cache mai sofisticate: prin asocierea fonturilor, imaginilor și stilurilor noastre, toate sunt guvernate de aceeași regulă. Aceasta înseamnă că, dacă schimbăm undeva o singură valoare hexagonală în CSS - o modificare care ar putea reprezenta până la șase octeți de date noi - trebuie să redescărcăm sute de kilobyți de stiluri, imagini și fonturi.

De fapt, fonturile sunt un infractor foarte rău aici: fonturile sunt foarte, foarte puțin probabil să se schimbe vreodată. Sunt o resursă foarte rar modificată. De fapt, tocmai am mers și am verificat un proiect de lungă durată la care lucram un alt client și cu mine: ultima modificare a CSS-ului lor a fost ieri; ultima modificare a fișierelor de fonturi a avut loc acum opt luni. Imaginați-vă că forțați un utilizator să descarce din nou aceste fonturi de fiecare dată când actualizați ceva din foaia de stil.

Codificarea Base64 înseamnă că nu putem ascunde în memorie lucrurile în funcție de rata lor de schimbare și înseamnă, de asemenea, că trebuie să memorăm în cache lucruri care nu au legătură oricând altceva se schimbă. Este o situație de pierdere-pierdere.

Aceasta este separarea de bază a preocupărilor: stocarea în cache a fonturilor mele nu ar trebui să depindă de stocarea în cache a imaginilor mele nu ar trebui să depindă de stocarea în cache a stilurilor mele.

Bine, deci să recapitulăm rapid:

  • Codificarea Base64 crește dimensiunea fișierelor în moduri pe care nu le putem atenua în mod eficient (de exemplu, Gzip). Această creștere a redării întârzie dimensiunea fișierului, deoarece se întâmplă cu o resursă de blocare a redării.
  • Codificarea Base64 forțează, de asemenea, activele non-critice pe calea critică. (de exemplu, imagini, fonturi) Acest lucru înseamnă că - în acest caz particular - în loc să fie nevoie să descărcăm 68K de CSS înainte de a putea începe redarea paginii, trebuie să descărcăm peste 3,4 ori suma respectivă. Îi ținem pe utilizator să aștepte elemente pe care inițial nu ar fi trebuit să le aștepte!
  • Codificarea Base64 forțează descărcarea tuturor octeților activului, chiar dacă nu vor fi folosiți niciodată. Aceasta este o risipă de resurse și, din nou, se întâmplă pe calea noastră critică.
  • Codificarea Base64 ne restricționează capacitatea de a memora în cache activele individual; imaginile și fonturile noastre sunt acum legate de aceleași reguli de stocare în cache ca și stilurile noastre și invers.

Una peste alta, este o situație destul de sumbră: evitați Base64.

Discuții de date

Tot acest articol a fost scris folosind lucruri pe care le știu deja. Nu am efectuat teste și nici nu am date: este doar modul în care funcționează browserele ™. Cu toate acestea, am decis să merg mai departe și să fac niște teste pentru a vedea exact la ce fel de fapte și cifre ne uităm. Accesați partea 2 pentru a citi mai multe.

Există câteva cazuri foarte excepționale în care poate fi sensibil, dar veți fi absolut sigur de aceste cazuri atunci când apar. Dacă nu sunteți absolut sigur, atunci probabil că nu este unul dintre aceste cazuri. Greșește întotdeauna din partea precauției și presupune că Base64 nu este abordarea corectă de adoptat. ↩

Deschideți foaia de stil în fila Surse Chrome, apăsați pictograma <> din partea stângă jos a fișierului, gata. ↩

Rulați comanda globală (: g) pe toate liniile; găsiți linii care conțin date: (/ data:) și ștergeți-le (/ d). ↩

Bună, sunt Harry. eu sunt un consultant premiat inginer de performanță web, designer, dezvoltator, scriitor, și vorbitor din Marea Britanie. Eu scrie, Tweet, vorbi, și cod de partajare despre măsurarea și îmbunătățirea vitezei amplasamentului. Ar trebui să mă angajezi.