13 lipca 2020

Jak wyeliminować zasoby blokujące renderowanie?

Kategoria: Web
Tagi: dla profesjonalistów,
Autor: Paweł Mansfeld

Jak wyeliminować zasoby blokujące renderowanie?

Przy każdej wizycie na stronie internetowej kod HTML, CSS i JS jest przekształcany w graficzny interfejs użytkownika. To jak napisana jest strona internetowa wpływa na jej szybkość, wydajność oraz na wskaźniki jakościowe, które są brane pod uwagę przy pozycjonowaniu.

W tym artykule poznamy i zbadamy:

  • czym jest ścieżka krytyczna renderowania,
  • poszczególne jej etapy,
  • możliwości jej optymalizacji,

aby osiągać jeszcze lepsze wyniki. Aby móc coś świadomie optymalizować konieczne jest poznanie podstaw teoretycznych z tej dziedziny oraz umiejętność mierzenia założonego celu.

Szybka i wydajna strona internetowa w mniejszym stopniu angażuje procesor, zużywa mniej transferu, energii i dostarcza lepszych doświadczeń użytkownikom. Wydajny kod HTML, CSS i JS spowoduje, że strona będzie działać płynnie także na słabszych i starszych urządzeniach. Wprowadzone ostatnio WebVitals czyli podstawowe wskaźniki internetowe takie jak FCP, FID, LCP i CLS pozwalają skutecznie mierzyć realną wydajność stron internetowych oraz zwracają uwagę deweloperów na istotne aspekty optymalizacji, która przyczynia się do większej dostępności stron niezależnie od jakości wykorzystywanych urządzeń czy konkretnej platformy. Jednym z najważniejszych pojęć jakie trzeba zrozumieć jest krytyczna ścieżka renderowania.

Wyeliminuj zasoby blokujące renderowanie – to taką uwagę otrzymamy w narzędziu PageSpeed Insights, jeżeli krytyczna ścieżka renderowania naszej strony wymaga optymalizacji. Kolejna uwaga, która też ma ścisły związek z krytyczną ścieżką renderowania to: Unikaj tworzenia łańcuchów żądań krytycznych.

Krytyczna ścieżka renderowania – definicja

Krytyczna ścieżka renderowania (ang Critical Rendering Path) – to sekwencja zdarzeń, które odpowiadają za wczytanie, przeanalizowanie i wyrenderowanie strony interntowej na podstawie kodu źródłowego HTML, CSS, JavaScript i innych dołączonych zasobów.

Jak działa renderowanie strony internetowej?

Krytyczna ścieżka renderowania dzieli się na kilka etapów.

Krytyczna ścieżka renderowania

Kiedy wpiszemy lub wkleimy adres URL w pasku adresu (lub klikniemy na link), przeglądarka wysyła żądanie HTTP do serwera.

Kod HTML strony internetowej, który wygląda przykładowo tak:

<!doctype html>
<html lang="pl">
   <head>
      <meta charset="utf-8">
      <title>Przykładowa strona internetowa</title>
      <meta name="viewport" content="width=device-width, initial-scale=1">
   </head>
   <body>
      <h1>Witaj!</h1>
      <img src="obrazek.jpg" alt="obrazek">
   </body>
</html>

jest przekształcany na to co widzimy w przeglądarce:

Wyrenderowana strona internetowa

I choć wydaje się to skomplikowane, to tak naprawdę sekwencja prostych instrukcji.

DOM

Przeglądarka buduje obiektowy model dokumentu, w skrócie: DOM (ang. Document Object Model). Specyfikacja języka HTML zawiera szczegółowe inforacje dla twórców przeglądarek jak przetwarzać otrzymane dane. Każdy znacznik HTML tzw. tag – np. <html> lub <p>, jest tokenizowany i przekształcany na węzeł (ang. node). Nasza przykładowa strona jest przeksztłacana na mniej-więcej takie drzewo:

Drzewo zawiera wszelkie elementy strony, relacje pomiędzy nimi (np. zagnieżdżenie) i ich zawartość. Drzewo DOM jest przekształceniem całej zawartości kodu HTML.

DOM jest budowany stopniowo, załadowanie np. górnej połowy kodu HTML umożliwia wygenerowanie górnej połowy drzewa DOM. Fakt ten wykorzystują przeglądarki (wczytują stronę w częściach) i można to wykorzystać w optymalizacji wydajności strony. Widać to szczególnie na stronach bardzo obszernych. Nawet bez wdrażania technik lazy-load widać skokowe pojawianie się strony a zdjęcia zawsze są ładowane z lekkim opóźnieniem.

Optymalizacja DOM

Powiedzieliśmy, że generowanie DOM w przeglądarce przebiega stopniowo. Z perspektywy optymalizacji możemy:

  • upraszczać i skracać kod HTML,
  • minifikować HTML,
  • minimalizować czas odpowiedzi serwera,
  • zapisywać HTML w pamięci podręcznej np. z wykorzystaniem nagłówków Last-Modified, Cache-Control i ETag.

CSSOM

Obiektowy model kaskadowych arkuszy stylów czyli CSSOM (ang. Cascading Style Sheets Object Model) działa analogicznie jednak istnieje pewna zasadnicza różnica.

Kod CSS, który wygląda np. tak:

body {
font-size: 16px;
}
p {
font-weight: bold;
}
span {
color:red;
}

jest zamieniany na CSSOM. Warto wiedzieć, że słowo “kaskadowy” wzięło się stąd, że reguły CSS przypisane do elementu nadrzędnego wpływają na styl elementów podrzędnych a każda kolejna reguła nadpisuje poprzednią o ile selektor był tak samo specyficzny. W przytoczonym wyżej przykładzie właściwość font-size przy elemencie body będzie też wpływać na wielkość tekstu zawartego w paragrafie. Choć daje to dużo swobody deweloperom, takie działanie CSS niestety uniemożliwia załadować górnej połowy kodu CSS w celu wygenerowania górnej połowy strony. W kolejnych liniach CSS można dodać kolejne reguły, które odnoszą się np. do całego elementu body.

To dlatego optymalizacja wydajności CSS jest tak problematyczna i dlatego mówimy, że plik z kodem CSS blokuje renderowanie strony, ponieważ musi być załadowany w całości aby nawet najmniejszy kawałek strony mógł być wyświetlony w przeglądarce.

Optymalizacja kroku CSSOM

Istnieją skuteczne techniki optymalizowania etapu CSSOM i krytycznej ścieżki renderowania. Jednym z nich jest wydzielenie krytycznego kodu CSS, który możemy dodać za pomocą standardowego i blokującego odwołania:

<link rel="stylesheet" href="styles.css">

Lub dodać ten kod w tagi <style> w nagłówku strony:

<style>
   body{
      background:#f8f8f8;
   }
</style>

Dodając krytyczny kod CSS bezpośrednio do kodu HTML, unikamy tworzenia łańcuchów żądań krytycznych. Nie musimy czekać na pobranie się pliku. Do tworzenia i wydłużenia łańcuchów żądań krytycznych przyczynia się też:

  • instrukcje import w kodzie CSS,
  • ładowanie niestandardowych fontów (zasoby wskazywane przez font src).

Aby cała optymalizacja miała jakikolwiek sens, krytyczny kod CSS musi być zwięzły (od kilku do kilkunastu kilobajtów), dotyczyć najważniejszych części strony (czyli najczęściej, menu głównego i nagłówków), oraz być wolny od nadmiarowych instrukcji. W przeciwnym razie staje się redundantny i w przypadku stron do których dochodzi do wielu wyświetleń podstron na jedną wizytę przynosi skutek odwrotny do zamierzonego.

Kodowi niekrytycznemu, który zawiera style elementów położonych niżej, można opóźnić ładowanie np. za pomocą takiej techniki:

<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>

Efekt jaki chcemy uzyskać to jak najszybsze pojawienie się góry strony a po jej załadowaniu, nieco opóźnione wygenerowanie się reszty strony np. stopki, która jest potrzebna nieco później i mniej istotnych elementów (np. filmu w tle czy animacji):

Kolejną techniką która zmniejsza blokowanie renderowania jest wykorzystanie zapytań medialnych:

<link rel="stylesheet" href="styles-desktop.css" media="(min-width: 1200px)">

Wartość w atrybucie media powoduje, ze plik jest ładowany tylko w przypadku korzystania z urządzenia o polu 1200px CSS, co w praktyce oznacza, że nie będzie on blokował wczytywania w przeglądarkach na urządzeniach desktop.

Należy pamiętać, że tak jak w przypadku kodu HTML, możemy usuwać nieużywane instrukcje CSS (zarówno w kodzie krytycznym i uzupełniającym), kompresować, minifikować i zapisywać w pamięci podręcznej pliki CSS. Sprawdź także inne techniki optymalizacji CSS.

Drzewo renderowania

Drzewo renderowania jest kombinacją drzewa DOM i CSSOM. Zawiera jednak tylko te elementy, które mają zostać wyświetlone na ekranie. W przypadku kiedy naszemu paragrafowi z napisem “lorem ipsum…” przypiszemy regułę p {display: none;} Nie zostanie on wzięty pod uwagę w drzewie renderowania. Element taki nie bierze udziału w kolejnych etapach czyli w układaniu i malowaniu.

Z tego wynika prosta porada optymalizacyjna: chcąc ukryć jakiś element na stronie (np. popup) z perspektywy wydajności lepiej jest ukryć go za pomocą CSSa niż za pomocą JavaScript.

Optymalizacja drzewa renderowania

Na końcowy kształt DOM, CSSSOM i drzewa renderowania mają także skrypty JavaScript. Aby JavaScript nie blokował drzewa renderowania można wykorzystać regułę async. Atrybut async powoduje, że kod JS jest wykonywany niezależnie od etapu ładowania się strony i nie wpływa na ścieżkę renderowania. Atrybut ten może być z powodzeniem zastosowany w przypadku skryptów do:

  • analityki internetowej,
  • dodatkowych widgetów do strony,
<srcipt src="analytics.js" async></script>

W pliku analytics.js umieszczamy kod, który miał być wklejony czy to do nagłówka czy przed znacznikiem zamykającym </body>. To mit, że jest tylko jeden poprawny sposób umieszczania jakiegoś skryptu na stronie. Pamiętaj, że instrukcja instalacji nie jest oficjalnym zaleceniem lub wymogiem.

W przypadku kiedy JavaScript manipuluje drzewem DOM, można wykorzystać defer. Dzięki temu, skrypty w nagłówku będą potraktowane z takim priorytetem, jakby były na samym końcu strony. W przypadku kiedy chcemy pogodzić asynchroniczne ładowanie i możliwość manipulacją drzewem DOM, można wykorzystać bibliotekę require.js.

Małe pliki JavaScript, które dokonują manipulacji w drzewie dom można wklejać w kod HTML za pomocą tagów <script>. Taki kod opóźni renderowanie (bo kodowi in-line nie można przypisać atrybutu async) ale zapobiegamy w ten sposób tworzenia łańcuchów żądań krytycznych.

W przypadku plików JS należy stosować uniwersalne techniki optymalizacji zasobów tekstowych jak w przypadku HTML i CSS a więc: możemy usuwać niepotrzebne instrukcje, kompresować, minifikować i zapisywać w pamięci podręcznej pliki JS. Sprawdź także inne techniki optymalizacji JavaScript pod kątem szybkości i wydajności stron internetowych.

Layout

Layout to etap w którym przeglądarka ustala pozycje i wymiary poszczególnych elementów z drzewa renderowania. To w tym etapie dokonuje się obliczeń ilości pikseli na podstawie relatywnych jednostek procentowych lub rem, które są wykorzystywane w przypadku stron z układem proporcjonalnym lub zgodnych z podejściem responsive web design.

“Układanie” strony ma miejsce nie tylko podczas pierwszego załadowania podstrony ale także w przypadku obrotu ekranu a także zmiany pola roboczego przeglądarki. Ponowny etap “layout” może być też wykonywany w przypadku efektów wizualnych. Optymalizacja kodu CSS i JS może polegać na tym aby

  • unikać powtarzania się tego procesu np. rozsuwając lub zmieniając wielkość elementów na stronie,
  • stosować zakodowane wartości width i height dla grafik,
  • zamiast animacji SVG stosować filmy mp4 lub rezygnować z tego typu efektów.

Malowanie

Malowanie to proces kolorowania konkretnych pikseli w widoku przeglądarki. Jest to ostatni etap renderowania i jest formalnością ponieważ w pełni zależy od poprzednich etapów. Malowanie musi być powtórzone za każdym razem kiedy zmieniamy drzewo DOM, CSSOM lub dochodzi do powtórnego layoutu np. w skutek obrócenia ekranu lub zmiany pola roboczego przeglądarki.

Podsumowanie

Dzięki optymalizacji krytycznej ścieżki renderowania wszystkie przeglądarki szybko i sprawnie są w stanie wyświetlić finalną zawartość jak to wynika z kodu źródłowego i dołączonych zasobów. Większa przyjazność dla urządzeń mobilnych, lepszy wynik wydajności i lepsze user experience wpłynie też pozytywnie na pozycje w wyszukiwarkach i nie będzie ograniczać strony w rozwoju i skalowaniu.

Strona bez balastu nadmiarowego kodu i praktyk deweloperskich które były wystarczając w ubiegłym dziesięcioleciu lepiej zrealizuje swoje cele biznesowe a osiągnięcie ogólnie rozumianego sukcesu będzie bardziej prawdopodobne. Stety albo niestety przewaga nawet o jeden punkt procentowy może zadecydować o zwycięstwie – na tym przecież polegają rankingi.

Źródła:

https://developers.google.com/web/fundamentals/performance/critical-rendering-path

Oceń artykuł na temat: Jak wyeliminować zasoby blokujące renderowanie?
Średnia : 4.8 , Maksymalnie : 5 , Głosów : 11


 

Odpowiedz lub skomentuj

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *




Komentarze

Filip

28 września 2020

Te kody html umieścić należy w headerze? To wszystko? Artykuł pisany jak dla developera. Ja, jako początkujący samouk, miałem pewne trudności ze zrozumieniem go. Pozdrawiam!

Paweł Mansfeld

28 września 2020

Tak, tego typu artykuły piszę dla deweloperów albo dla power-userów systemów CMS. Jak zabieramy się sami za tego typu edycje, musimy znać chociaż podstawy HTML, CSS i JS.

W sieci jest wiele poradników, które tłumaczą jak rozwiązać problem wtyczkami bez konieczności wnikania w technikalia ale jak się sam przekonałeś ich użyteczność jest - mówiąc delikatnie - niska :) Ja też byłem na etapie gdzie nie rozumiałem podobnych poradników - kwestia czasu.

Mam nadzieję, że za jakiś czas wrócisz na tego bloga i w komentarzach będziesz mi wytykał błędy lub proponował lepsze rozwiązania dla poruszanych problemów :). Dzięki za komentarz i pozdrawiam.

 

Następny artykuł

Wykryto brak połączenia z Internetem.