Refactorizarea CSS: optimizarea dimensiunii și performanței (partea a 3-a)
Publicat: 2022-03-10În articolele anterioare din această serie, am abordat auditarea sănătății bazei de cod CSS și strategia de refactorizare CSS incrementală, testare și întreținere. Indiferent de cât de mult a fost îmbunătățită baza de cod CSS în timpul procesului de refactorizare și cât de mult mai ușor de întreținut și extins este, foaia de stil finală trebuie optimizată pentru cea mai bună performanță posibilă și dimensiunea fișierului cât mai puțin posibilă.
Implementarea bazei de cod refactorizat nu ar trebui să aibă ca rezultat o performanță mai slabă a site-ului web și o experiență mai proastă a utilizatorului. La urma urmei, utilizatorii nu vor aștepta pentru totdeauna ca site-ul web să se încarce. De asemenea, conducerea va fi nemulțumită de scăderea traficului și a veniturilor cauzate de baza de cod neoptimizată, în ciuda îmbunătățirilor calității codului.
În acest articol, vom acoperi strategiile de optimizare CSS care pot optimiza dimensiunea fișierului CSS, timpii de încărcare și performanța de randare. În acest fel, baza de cod CSS refactorizată nu este doar mai menținută și extensibilă, ci și mai performantă și bifează toate casetele care sunt importante atât pentru utilizatorul final, cât și pentru management.
Parte din: Refactorizarea CSS
- Partea 1: Refactorizarea CSS: Introducere
- Partea 2: Strategia CSS, testarea regresiei și întreținerea
- Partea 3: Optimizarea dimensiunilor și performanței
- Abonați-vă la newsletter-ul nostru prin e-mail pentru a nu rata următoarele.
Optimizarea dimensiunii fișierului foaie de stil
Optimizarea dimensiunii fișierului se rezumă la eliminarea caracterelor inutile și formatarea și optimizarea codului CSS pentru a utiliza diferite proprietăți de sintaxă sau prescurtare pentru a reduce numărul total de caractere dintr-un fișier.
Optimizare și minimizare
Optimizarea și minificarea CSS există de ani de zile și au devenit un element de bază în optimizarea frontend. Instrumente precum cssnano și clean-css sunt printre instrumentele mele preferate când vine vorba de optimizarea și minificarea CSS. Ele oferă o mare varietate de opțiuni de personalizare pentru a controla în continuare modul în care codul este optimizat și ce browsere sunt acceptate.
Aceste instrumente funcționează într-un mod similar. În primul rând, codul neoptimizat este analizat și transpilat urmând regulile stabilite în config. Rezultatul este codul care folosește mai puține caractere, dar păstrează totuși formatarea (întreruperi de linie și spații albe).
/* Before - original and unoptimized code */ .container { padding: 24px 16px 24px 16px; background: #222222; } /* After - optimized code with formatting */ .container { padding: 24px 16px; background: #222; }
Și, în cele din urmă, codul optimizat transpilat este redus prin eliminarea tuturor formatărilor inutile ale textului . În funcție de baza de cod și de browserele acceptate setate în configurație, codul cu prefixe de furnizor învechite poate fi, de asemenea, eliminat.
/* Before - optimized code with formatting */ .container { padding: 24px 16px; background: #222; } /* After - optimized and minified code */ .container{padding:24px 16px;background:#222}
Chiar și în acest exemplu de bază, am reușit să reducem dimensiunea totală a fișierului de la 76 de octeți la 55 de octeți, rezultând o reducere de 23%. În funcție de baza de cod și de instrumentele de optimizare și de configurare, optimizarea și minimizarea CSS pot fi și mai eficiente.
Optimizarea și minimizarea CSS pot fi considerate drept o victorie ușoară datorită câștigului semnificativ cu doar câteva modificări ale fluxului de lucru CSS. De aceea, minimizarea ar trebui tratată ca optimizarea minimă a performanței și o cerință pentru toate foile de stil din proiect.
Optimizarea interogărilor media
Când scriem interogări media în CSS, mai ales când folosim mai multe fișiere (PostCSS sau Sass), de obicei nu imbricam codul sub o singură interogare media pentru un întreg proiect. Pentru o întreținere îmbunătățită, modularitate și structură de cod, de obicei scriem aceleași expresii de interogare media pentru mai multe componente CSS.
Să luăm în considerare următorul exemplu de bază de cod CSS neoptimizat.
.page { display: grid; grid-gap: 16px; } @media (min-width: 768px) { .page { grid-template-columns: 268px auto; grid-gap: 24px; } } /* ... */ .products-grid { display: grid; grid-template-columns: repeat(2, 1fr); grid-gap: 16px; } @media (min-width: 768px) { .products-grid { grid-template-columns: repeat(3, 1fr); grid-gap: 20px; } }
După cum puteți vedea, avem un @media (min-width: 768px)
per componentă pentru o mai bună lizibilitate și întreținere. Să rulăm optimizarea și minimizarea acestui exemplu de cod și să vedem ce obținem.
.page{display:grid;grid-gap:16px}@media (min-width: 768px){.page{grid-template-columns:268px auto;grid-gap:24px}}.products-grid{display:grid;grid-template-columns:repeat(2,1fr);grid-gap:16px}@media (min-width: 768px){.products-grid{grid-template-columns:repeat(3,1fr);grid-gap:20px}}
Acest lucru ar putea fi puțin dificil de citit, dar tot ce trebuie să observăm este interogarea media repetată @media (min-width: 768px)
. Am ajuns deja la concluzia că dorim să reducem numărul de caractere dintr-o foaie de stil și că putem imbrica mai multe selectoare într-o singură interogare media, așa că de ce nu a eliminat minificatorul expresia duplicată? Există un motiv simplu pentru asta.
Ordinea regulilor contează în CSS, așa că pentru a îmbina interogările media duplicate, blocurile de cod trebuie mutate. Acest lucru va duce la modificarea ordinelor regulilor, ceea ce poate provoca efecte secundare nedorite în stiluri.
Cu toate acestea, combinarea interogărilor media ar putea face dimensiunea fișierului și mai mică, în funcție de baza de cod și de structură. Instrumente și pachete precum postcss-sort-media-queries ne permit să eliminăm interogările media duplicate și să reducem și mai mult dimensiunea fișierului.
Desigur, există o avertizare importantă de a avea o structură de bază de cod CSS bine structurată, care nu depinde de ordinea regulilor. Această optimizare ar trebui să fie luată în considerare la planificarea refactorului CSS și la stabilirea regulilor de bază.
Aș recomanda mai întâi să verificați dacă beneficiul optimizării depășește riscurile potențiale. Acest lucru se poate face cu ușurință prin rularea unui audit CSS și verificarea statisticilor de interogare media. Dacă o face, aș recomanda să îl adăugați mai târziu și să rulați testarea automată de regresie pentru a detecta orice efecte secundare neașteptate și erori care se pot întâmpla ca rezultat.
Eliminarea CSS neutilizat
În timpul procesului de refactorizare, există întotdeauna posibilitatea ca să ajungeți cu unele stiluri moștenite neutilizate care nu au fost complet eliminate sau să aveți unele stiluri nou adăugate care nu sunt folosite. Aceste stiluri se adaugă, de asemenea, la numărul total de caractere și la dimensiunea fișierului. Eliminarea acestor stiluri neutilizate folosind instrumente automate, totuși, poate fi oarecum riscantă, deoarece instrumentele nu pot prezice cu exactitate ce stiluri sunt utilizate efectiv.
Instrumente precum purgecss parcurg toate fișierele din proiect și folosesc toate clasele menționate în fișiere ca selectoare, doar pentru a greși din partea precauției și pentru a nu șterge accidental selectoare pentru elemente dinamice, injectate de JavaScript, printre alte cazuri potențiale. Cu toate acestea, purgecss oferă opțiuni de configurare flexibile ca soluții pentru aceste probleme și riscuri potențiale.
Cu toate acestea, această îmbunătățire ar trebui făcută numai atunci când beneficiile potențiale depășesc riscurile . În plus, această tehnică de optimizare va necesita timp considerabil pentru configurare, configurare și testare și ar putea cauza probleme neintenționate în continuare, așa că procedați cu prudență și asigurați-vă că configurarea este rezistentă la glonț.
Eliminarea CSS care blochează randarea
În mod implicit, CSS este o resursă care blochează randarea, ceea ce înseamnă că site-ul web nu va fi afișat utilizatorului până când toate foile de stil legate și dependențele acestora (fonturile, de exemplu) nu vor fi descărcate și analizate de browser.
Dacă fișierul foaie de stil are o dimensiune mare a fișierului sau dependențe multiple care se află pe servere terțe sau pe CDN-uri, redarea site-ului web poate fi întârziată semnificativ în funcție de viteza și fiabilitatea rețelei.
Cel mai mare conținut de vopsea (LCP) a devenit o măsură importantă în ultimele luni. LCP nu este important doar pentru performanță, ci și pentru SEO - site-urile web cu scoruri LCP mai bune vor avea o clasare mai bună în rezultatele căutării. Eliminarea resurselor care blochează randarea, cum ar fi CSS, este o modalitate de a îmbunătăți scorul LCP.
Cu toate acestea, dacă am amâna încărcarea și procesarea foii de stil, aceasta ar avea ca rezultat Flash Of Unstyled Content (FOUC) - conținutul ar fi afișat utilizatorului imediat, iar stilurile ar fi încărcate și aplicate câteva momente mai târziu. Acest comutator ar putea părea tulburător și poate chiar deruta unii utilizatori.
CSS critic
Cu Critical CSS, ne putem asigura că site- ul web se încarcă cu cantitatea minimă de stiluri care sunt garantate a fi utilizate pe pagină atunci când este redată inițial. În acest fel, putem face FOUC mult mai puțin vizibil sau chiar îl putem elimina în majoritatea cazurilor. De exemplu, dacă pagina de pornire prezintă o componentă antet cu navigare și o componentă erou situată deasupra paginii, aceasta înseamnă că CSS-ul critic va conține toate stilurile globale și componente necesare pentru aceste componente, în timp ce stilurile pentru alte componente de pe pagină va fi amânat.
Acest CSS este aliniat în HTML sub o etichetă de style
, astfel încât stilurile sunt încărcate și analizate alături de fișierul HTML. Deși acest lucru va duce la o dimensiune a fișierului HTML puțin mai mare (care ar trebui, de asemenea, redusă), toate celelalte CSS necritice vor fi amânate și nu vor fi încărcate imediat, iar site-ul web va fi redat mai rapid. Una peste alta, beneficiile depășesc creșterea dimensiunii fișierului HTML.
<head> <style type="text/css"><!-- Minified Critical CSS markup --></style> </head>
Există multe instrumente automate și pachete NPM, în funcție de configurația dvs., care pot extrage CSS critic și pot genera foi de stil amânate.
Amânarea foilor de stil
Cum facem exact ca CSS să fie non-blocant? Știm că nu ar trebui să fie referit în elementul head
HTML atunci când pagina HTML este descărcată pentru prima dată. Demian Renzulli a subliniat această metodă în articolul său.
Nu există o abordare HTML nativă (deocamdată) pentru a optimiza sau a amâna încărcarea resurselor de blocare a randării, așa că trebuie să folosim JavaScript pentru a insera foaia de stil non-critică în marcajul HTML după randarea inițială. De asemenea, trebuie să ne asigurăm că aceste stiluri sunt încărcate într-un mod neoptim (de blocare a randării) dacă un utilizator vizitează pagina cu JavaScript neactivat în browser.
<!-- Deferred stylesheet --> <link rel="preload" as="style" href="path/to/stylesheet.css" onload="this.onload=null;this.rel='stylesheet'"> <!-- Fallback --> <noscript> <link rel="stylesheet" href="path/to/stylesheet.css"> </noscript>
Cu link rel="preload" as="style"
se asigură că fișierul foaie de stil este solicitat asincron, în timp ce onload
JavaScript handler se asigură că fișierul este încărcat și procesat de browser după ce documentul HTML s-a terminat de încărcat. Este nevoie de puțină curățare, așa că trebuie să setăm onload
-ul la null
pentru a evita ca această funcție să ruleze de mai multe ori și să provoace re-rendări inutile.
Exact așa își gestionează Smashing Magazine foile de stil. Fiecare șablon (pagină de pornire, categorii de articole, pagini de articole etc.) are un CSS critic specific șablonului încorporat în interiorul etichetei de style
HTML în elementul head
și o foaie de stil main.css
amânată care conține toate stilurile care nu sunt critice.
Cu toate acestea, în loc să comutăm parametrul rel
, aici putem vedea că interogarea media este comutată de la suportul de print
cu prioritate scăzută amânată automat la atributul cu prioritate înaltă all
atunci când pagina s-a terminat de încărcat. Aceasta este o abordare alternativă, la fel de viabilă, pentru a amâna încărcarea foilor de stil non-critice.
<link href="/css/main.css" media="print" onload="this.media='all'" rel="stylesheet">
Împărțirea și încărcarea condiționată a foilor de stil cu interogări media
Pentru cazurile în care fișierul final al foii de stil are o dimensiune mare a fișierului chiar și după ce au fost aplicate optimizările menționate mai sus, puteți împărți foile de stil în mai multe fișiere pe baza interogărilor media și puteți utiliza proprietatea media pe foile de stil la care se face referire în elementul HTML pentru a le încărca condiționat. .
<link href="print.css" rel="stylesheet" media="print"> <link href="mobile.css" rel="stylesheet" media="all"> <link href="tablet.css" rel="stylesheet" media="screen and (min-width: 768px)"> <link href="desktop.css" rel="stylesheet" media="screen and (min-width: 1366px)">
În acest fel, dacă se folosește o abordare bazată pe mobil, stilurile pentru ecrane de dimensiuni mai mari nu vor fi descărcate sau analizate pe dispozitivele mobile care ar putea rula pe rețele mai lente sau nesigure.
Pentru a reitera, această metodă ar trebui folosită dacă rezultatul metodelor de optimizare menționate anterior are ca rezultat o foaie de stil cu dimensiunea fișierului suboptimă. Pentru cazurile obișnuite, această metodă de optimizare nu va fi la fel de eficientă sau de impact, în funcție de dimensiunea individuală a foii de stil.
Amânarea fișierelor de font și a foilor de stil
Amânarea foilor de stil pentru font (fișierele Google Font, de exemplu) ar putea fi, de asemenea, benefică pentru performanța inițială a randării. Am ajuns la concluzia că foile de stil blochează randarea, dar la fel sunt și fișierele cu fonturi la care se face referire în foaia de stil. Fișierele cu font adaugă, de asemenea, destul de multă supraîncărcare la performanța de randare inițială.
Încărcarea foilor de stil pentru fonturi și a fișierelor cu fonturi este un subiect complex, iar scufundarea în el ar fi nevoie de un articol complet nou doar pentru a explica toate abordările viabile. Din fericire, Zach Leatherman a subliniat multe strategii viabile în acest ghid cuprinzător minunat și a rezumat avantajele și dezavantajele fiecărei abordări. Dacă utilizați Google Fonts, Harry Roberts a schițat o strategie pentru cea mai rapidă încărcare a Google Fonts.
Dacă decideți să amânați foile de stil pentru fonturi, veți ajunge la Flash of Unstyled Text (FOUT). Pagina va fi redată inițial cu fontul alternativ până când fișierele de fonturi amânate și foile de stil vor fi descărcate și analizate, moment în care noile stiluri vor fi aplicate. Această modificare poate fi foarte vizibilă și poate provoca schimbări de aspect și poate deruta utilizatorii, în funcție de caz individual.
Barry Pollard a subliniat câteva strategii care ne pot ajuta să ne ocupăm de FOUT și a vorbit despre viitoarea caracteristică CSS de ajustare a dimensiunii, care va oferi un mod mai ușor și mai nativ de a trata cu FOUT.
Optimizări la nivelul serverului
Compresie HTTP
Pe lângă minimizarea și optimizarea dimensiunii fișierelor, activele statice precum HTML, fișiere CSS, fișiere JavaScript etc. Algoritmii de compresie HTTP precum Gzip și Brotli pot fi utilizați pentru a reduce suplimentar dimensiunea fișierului descărcat.
Compresia HTTP trebuie configurată pe server, ceea ce depinde de stiva tehnologică și de configurare. Cu toate acestea, beneficiile de performanță pot varia și pot să nu aibă un impact la fel de mare ca minimizarea și optimizarea standard a foii de stil, deoarece browserele vor decomprima în continuare fișierele comprimate și vor trebui să le analizeze.
Memorarea în cache a foilor de stil
Memorarea în cache a fișierelor statice este o strategie utilă de optimizare. Browserele vor trebui în continuare să descarce fișierele statice de pe server la prima încărcare, dar odată ce vor fi stocate în cache, vor fi încărcate direct de pe acesta la solicitările ulterioare, accelerând procesul de încărcare.
Memorarea în cache poate fi controlată prin antetul HTTP Cache-Control la nivel de server (de exemplu, folosind fișierul .htaccess
pe un server Apache).
Cu max-age
putem indica cât timp fișierul ar trebui să rămână în cache (în secunde) în browser și cu public
, indicăm că fișierul poate fi stocat în cache de browser și de orice alte cache.
Cache-Control: public, max-age=604800
O strategie de cache mai agresivă și mai eficientă pentru activele statice poate fi realizată cu configurația immutable
. Acest lucru îi spune browserului că acest anumit fișier nu se va modifica niciodată și că orice actualizări noi va duce la ștergerea acestui fișier și va lua locul unui fișier nou cu un alt nume de fișier. Acest lucru este cunoscut sub numele de cache-busting .
Cache-Control: public, max-age=604800, immutable
Fără o strategie adecvată de eliminare a memoriei cache , există riscul de a pierde controlul asupra fișierelor care sunt stocate în cache în browserul utilizatorului. Înseamnă că, dacă fișierul s-ar modifica, browserul nu va putea ști că ar trebui să descarce fișierul actualizat și să nu folosească fișierul învechit din cache. Și din acel moment, practic nu putem face nimic pentru a remedia asta, iar utilizatorul va rămâne blocat cu fișierul învechit până când acesta expiră.
Pentru foile de stil, asta ar putea însemna că, dacă ar fi să actualizăm fișierele HTML cu conținut nou și componente care necesită stil nou, aceste stiluri nu se vor afișa deoarece foaia de stil învechită este stocată în cache fără o strategie de eliminare a memoriei cache și browserul nu va ști că trebuie să descarce noul fișier.
Înainte de a utiliza o strategie de stocare în cache pentru foile de stil sau orice alte fișiere statice, ar trebui implementate mecanisme eficiente de eliminare a memoriei cache pentru a preveni blocarea fișierelor statice învechite în memoria cache a utilizatorului. Puteți utiliza unul dintre următoarele mecanisme de versiune pentru eliminarea cache-ului:
- Adăugarea unui șir de interogare la numele fișierului.
De exemplustyles.css?v=1.0.1.
Cu toate acestea, unele CDN-uri pot ignora complet sau elimina șirul de interogare din numele fișierului, ceea ce duce la blocarea fișierului în memoria cache a utilizatorului și nu se actualizează niciodată. - Schimbarea numelui fișierului sau adăugarea unui hash.
De exemplustyles.a1bc2.css
saustyles.v1.0.1.css.
Acest lucru este mai fiabil și mai eficient decât adăugarea unui șir de interogare la numele fișierului.
CDN sau self-hosting?
Content Delivery Network (CDN) este un grup de servere distribuite geografic care sunt utilizate în mod obișnuit pentru livrarea fiabilă și rapidă a activelor statice, cum ar fi imagini, videoclipuri, fișiere HTML, fișiere CSS, fișiere JavaScript etc.
Deși CDN-urile ar putea părea o alternativă excelentă la activele statice de auto-găzduire, Harry Roberts a făcut cercetări aprofundate pe această temă și a concluzionat că activele de auto-găzduire sunt mai benefice pentru performanță.
„Există foarte puține motive pentru a lăsa activele tale statice pe infrastructura altcuiva. Beneficiile percepute sunt adesea un mit și, chiar dacă nu ar fi, compromisurile pur și simplu nu merită. Încărcarea activelor din mai multe origini este evident mai lentă.”
Acestea fiind spuse, aș recomanda găzduirea automată a foilor de stil (foile de stil cu fonturi incluse, dacă este posibil) în mod implicit și mutarea la CDN numai dacă există motive viabile sau alte beneficii pentru a face acest lucru.
Auditarea dimensiunii și performanței fișierului CSS
WebPageTest și alte instrumente similare de auditare a performanței pot fi folosite pentru a obține o imagine de ansamblu detaliată a procesului de încărcare a site-ului web, a dimensiunilor fișierelor, a resurselor de blocare a redării etc. Aceste instrumente vă pot oferi o perspectivă asupra modului în care site-ul dvs. se încarcă pe o gamă largă de dispozitive - de la un PC desktop care rulează pe o rețea de mare viteză până la smartphone-uri de gamă joasă care rulează pe rețele lente și nesigure.
Să facem un audit de performanță pe un site web menționat în primul articol din această serie — cel cu cei 2 MB de CSS minificat.
În primul rând, vom arunca o privire asupra defalcării conținutului pentru a determina care resurse ocupă cea mai mare lățime de bandă. Din diagramele următoare, putem vedea că imaginile preiau cele mai multe solicitări, ceea ce înseamnă că trebuie să fie încărcate leneș. Din a doua diagramă, putem vedea că foile de stil și fișierele JavaScript sunt cele mai mari în ceea ce privește dimensiunea fișierului. Acesta este un bun indiciu că aceste fișiere trebuie fie să fie reduse și optimizate, refactorizate, fie împărțite în mai multe fișiere și încărcate asincron.
Putem trage și mai multe concluzii din diagramele Web Vitals. Aruncând o privire la diagrama cea mai mare vopsea de conținut (LCP), putem obține o imagine de ansamblu detaliată a resurselor care blochează randarea și cât de mult afectează randarea inițială.
Am putea deja concluzia că foaia de stil a site-ului web va avea cel mai mare impact asupra LCP și statisticile de încărcare. Cu toate acestea, putem vedea foi de stil pentru fonturi, fișiere JavaScript și imagini la care se face referire în foile de stil care blochează și randarea. Știind că putem aplica metodele de optimizare menționate mai sus pentru a reduce timpul LCP prin eliminarea resurselor de blocare a randării.
Concluzie
Procesul de refactorizare nu este complet atunci când sănătatea și calitatea codului au fost îmbunătățite și când slăbiciunile și problemele bazei de cod au fost remediate. Baza de cod refactorizată ar trebui să aibă ca rezultat performanță identică sau îmbunătățită în comparație cu baza de cod moștenită.
Utilizatorii finali nu ar trebui să se confrunte cu probleme de performanță sau timpi lungi de încărcare din baza de cod refactorizat. Din fericire, există multe metode pentru a vă asigura că bazele de cod sunt atât robuste, cât și performante - de la metodele simple de minimizare și optimizare până la metode mai complexe, cum ar fi eliminarea resurselor de blocare a redării și împărțirea codului.
Putem folosi diverse instrumente de auditare a performanței, cum ar fi WebPageTest , pentru a obține o imagine de ansamblu detaliată a timpilor de încărcare, a performanței, a resurselor de blocare a randării și a altor factori, astfel încât să putem aborda aceste probleme devreme și eficient.
Parte din: Refactorizarea CSS
- Partea 1: Refactorizarea CSS: Introducere
- Partea 2: Refactorizarea CSS: strategie, testare de regresie și întreținere
- Partea 3: Refactorizare CSS: Optimizarea dimensiunii și performanței
- Abonați-vă la newsletter-ul nostru prin e-mail pentru a nu rata următoarele.
Referințe
- „Render Blocking CSS”, Ilya Grigorik
- „Amână CSS non-critic”, Demian Renzulli
- „Un ghid cuprinzător pentru strategiile de încărcare a fonturilor”, Zach Leatherman
- „Un nou mod de a reduce impactul încărcării fonturilor: descriptori de font CSS”, Barry Pollard
- „Găzduiește-ți activele statice”, Harry Roberts
- „Optimizați încărcarea și redarea fonturilor web”, Ilya Grigorik