O rychlosti webu, asynchronním načítání, kritických CSS a osudu zlatých kolovrátků

Vydal Jan Bien | 06/2015 | Trvalý odkaz | Komentáře (7)

Rychlost načítání webu se může zaseknout na mnoha místech. Jak tato úzká hrdla eliminovat? Odkazy na hromadu nástrojů included.

Pár týdnů jsem nebyl na žádném školení, tak jsem si udělal radost a nadělil si pokročilý responzivní design u Martina Michálka. Velká část dne jsme si povídali o rychlosti načítání webů, která je na datových tarifech žalostná. Rád bych si sesumíroval všechny s tím související myšlenky, dokud je mám v hlavě.

Pokud jde o rychlost webu, tak jako webmasteři tradičně uvažujeme o celkové velikosti stránky. Snažíme se stačit celkovou velikost stránky o těch pár desítek nebo stovek kB. Je to přístup legitimní, avšak těžkopádný, tvrdý a nemusí být ani moc efektivní. Může vést také k celkovému ochuzení webu o uživatelský zážitek, přehnané kompresi obrázků, k tvorbě nudných webů z minulého století, či k zapomenutí na dobré vývojářské návyky.

Ono totiž možná není až tak úplně důležité, jak dlouho tvá načtení celého webu (skutečná rychlost), ale spíše, jak je servírován uživateli (vnímaná rychlost). Odstrašující příklad, jak servírovat uživateli web, je velký kolovrátek přes celý web, který zmizí a zobrazí web, až se vše kompletně načte a zpracuje. (A to si chtěl uživatel zrovna jen zjistit telefonní číslo z hlavičky webu.)

Zřejmě lepší je dělat to přesně naopak. Snažit se co nejméně blokovat zobrazování a obsah servírovat postupně. Principy v bodech:

Problém bílé obrazovky

Celou tu problematiku lze demonstrovat na problému tzv. “času bílé obrazovky”. To je čas mezi chvílí, když uživatel zadal adresu webu a chvílí, kdy se mu web zobrazí. Čím je kratší tento čas, tím lépe. Každá vteřina má negativní dopad v jednotkách (a někdy i desítkách) procent na konverzích, počtu zhlédnutých stránek, atd…

O co v principu jde? Když prohlížeč načítá HTML stránku, tak analyzuje kód stránky a hledá další připojené zdroje (styly, scripty, fonty, obrázky, …) a tyto zdroje zařazuje do fronty stahování. Zdroje dělíme a) na ty, co blokují vykreslení stránky a b) na ty, to co ho neblokují. Ty blokující nám dělají problém, protože prohlížeč stránku zobrazí až ve chvíli, když stáhne všechny blokující zdroje.

Tak, a teď už postupně přejdu do technické řeči.

Eliminace blokujícího obsahu

To je ta hláška “Eliminujte v obsahu nad okrajem kód JavaScript a CSS blokující vykreslení.”, kterou vrací Google PageSpeed Insight. Blokující zdroje jsou: všechny css styly připojené prvkem <link> + všechny standardně načítané scripty. Neblokující zdroje jsou pak jsou obrázky, iframy a asynchronně načítané scripty.

Když z hlavičky vyhodím všechny při<link>ované css styly a všechny připojené scripty, stránka se vykreslí ihned po stažení HTML (tedy po jednom http požadavku a stažení velikosti stránky).

CSS styly pak připojím asynchronně javascriptem. Na to se hodí třeba knihovna enhance.js. A zároveň standardně prvkem <link> v prvku <noscript> pro nejavascriptovou minoritu.

Tímto způsobem dokážu hodně výrazně zkrátit čas bílé obrazovky (i na zlomek původního času).

Critical css

Při asynchronním načítání stylů ale dochází k jinému problému, který zvu “čas nenastylované obrazovky”. Dokud se nenačtou styly, tak uživatel vidí ošklivou stránku bez stylů. To se řeší tím, že se přímo v HTML kódu hlavičky stránky servírují “kritické CSS”, které nastylují kritickou viditelnou část stránky (tzv. nad foldem).

progressive-rendering

Ručně vytvářet kritické CSS by bylo příliš drahé a je lepší je vygenerovat.  Pokud bych se staral o jeden-dva weby, vystačil bych si s online generátorem Critical Path CSS Generator od Jonase Ohlssona. Pro solidní produkci je to nezbytné automatizovat. K tomu jsou skvělé criticalCSS pro gulp či grunt, které fungují nad neviditelným prohlížečem PhantomJs.

Kritické styly by bylo ideální servírovat jen při prvním načtení. Poté už má uživatelův prohlížeč css soubor nakešovaný, nebude tedy již zdržovat. To se řeší uložením cookie, jejíž existence se ověřuje při generování stránky. Kritické CSS se vypisují jen tehdy, pokud cookie neexistuje. Toto ovšem může být za hranicí realizovatelnosti, pokud používám nějaké serverové kešování.

Kritických CSS se pro jeden web generuje více. V principu, co typová stránka, to jeden kritický CSS.

Asynchronní načítání scriptů

Pak je otázka, kam kde, a jak linkovat scripty.

  1. Běžné připojení <scriptem> v <head> blokuje stahování. S atributy async/defer neblokuje, ale bohužel nefunguje v IE9- a Android2.  Atribut async zajistí asynchronní stažení a bezprostřední interpretování. Atribut defer zajistí interpretaci až po připraveném DOM a lze jím řídit pořadí. Více o tom u Tomáše Matonohy.
  2. Před </body> se začne stahovat pozdě.
  3. V <head> javascriptem, třeba funkcí loadJS() z knihovny enahnce.js. To se jeví jako nejlepší varianta.

Flash of Unstiled Text

FOIT (nebo někdy FOUT)  je takový blbé chování, když je ve stránce custom font. Ve chvíli, kdy se font začne stahovat, tak prohlížeč všechen text tímto fontem psaný skryje. Řeší se to javascriptem, který k dokumentu přiřazuje třídy podle stavu načítání. Rodina fontu se pak přiřazuje k prvkům až přes třídu, které indikuje úspěšné stažení fontu.

Pro vlastní hostované fonty je na to hotová pěkná knihovna Font Face Observer. Pro fonty z Google Fonts a Adobe TypeKit se na to hodí Web Font LoaderAdobe TypeKit to ale už taky umí přímo.

Závazek do budoucna

Celý tento přístup na mě klade docela velký závazek. Uživatele pouštím ke stránce, která je nehotová. Měl bychom pracovat se stavy, aby uživatel vnímal, že stránka se stránka stále načítá a pracuje tedy s omezenou funkčností a vzhledem. Neměl by to považovat za chybu.

Vtipné je, že velká část z těchto postupů bude docela pasé, až se rozšíří HTTP 2. Každopádně se myslím, že v tomto směry jsme my webmasteři a webdevelopeři vlastně spíš za začátku. Hodně experimentování a hledání postupů nás ještě čeká.

Doporučené nástroje: Google PageSpeed InsightWebPagetest  + Chrome DevTools.

Pro WordPress na to je docela hezký plugin Above The Fold Optimization, který by se mohl hodit ne-kodérům a ne-vývojářům.

Další pěkné čtení o tématu od Bohumila Jahody, Petra Soukupa a samozřejmě Martina Michálka. Pro podrobné studium obsáhlá Google příručka Web Fundamentals – Optimizing Performance.

Tož tak.

O autorovi

Jan Bien
Jan Bien
Jako kluk jsem si hrál se stavebnicí Merkur, kterou jsem v dospělosti (lze-li o něčem takovém u muže vůbec mluvit) vyměnil za WordPress. S WordPressem kouzlím zajímavé weby, radím lidem, zda je WordPress dobrý nápad pro konkrétní projekt, a občas koučuji jiné freelancery, co a jak s WordPressem podniknout ke spokojenosti své i svých klientů.

7 komentářů: “O rychlosti webu, asynchronním načítání, kritických CSS a osudu zlatých kolovrátků”

  1. Souki.cz napsal:

    HTTP/2 (resp. SPDY) se nijak neřešilo?

  2. Jan Bien Jan Bien napsal:

    Neřešilo … zřejmě Martin zařadí do “krajně pokročilého” kurzu ;)

  3. Souki.cz napsal:

    Díky HTTP/2 se totiž výrazně mění doporučení na optimalizace. Například dříve doporučované spojování obrázků do sprites už je teď naopak škodlivé.

  4. Souki.cz napsal:

    Ehm… teď jsem si všiml, že je to zmíněno v závěru a já to přehlédl :)

  5. Radek P. napsal:

    Zas je co číst. Zdrojů o tomhle je jak šafránu. Díky za odkazy na scripty

  6. Martin Držka napsal:

    Díky za shrnutí. Jen doplním, že FOIT a FOUT jsou rozdílná chování. FOIT (Flash of Invisible Text) nenačte fallback fonty vůbec a čeká na načtení @font-face. FOUT (Flash of Unstyled Text) je chování, kdy se vykreslí fallback font (systémový), který poté flashne na načtený @font-face. Většina browserů ma 3s timeout do kdy NEzobrazí falback font (FOUT) – očekává se, že do té doby načte @font-face. Návrhy jak to řešit na straně CSS https://github.com/KenjiBaheux/css-font-rendering i JS API http://dev.w3.org/csswg/css-font-loading/

  7. Martin Michálek napsal:

    Doplním jen doplnění Martina Držky – pokud se nepletu, FOIT zavedly prohlížeče, aby se vyhnuly FOUT. :) Tzn. v dnešních prohlížečích je problém hlavně FOIT.

    Tady je skvělý popis problému: https://dev.opera.com/articles/better-font-face/. A tady i popis řešení co používám na školení: https://jonsuh.com/blog/font-loading-with-font-events/

    Honzovi ještě jednou děkuji za sepsání.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *