Optymalizacja największego wyrenderowania treści

Szczegółowy przewodnik, jak analizować LCP i określać kluczowe obszary wymagające poprawy.

Data publikacji: 30 kwietnia 2020 r.

Największe wyrenderowanie treści (LCP) to jeden z 3 podstawowych wskaźników internetowych, który określa, jak szybko wczytują się główne treści strony. Wskaźnik LCP mierzy czas od momentu, gdy użytkownik rozpoczyna wczytywanie strony, do momentu wyrenderowania największego obrazu lub bloku tekstu w widocznym obszarze.

Aby wygodnie korzystać z witryny, w przypadku co najmniej 75% wizyt LCP powinien wynosić 2,5 sekundy lub mniej.

Dobre wartości LCP to 2,5 sekundy lub mniej, złe wartości to więcej niż 4,0 sekundy, a wszystko pomiędzy wymaga poprawy
Dobry wynik LCP to 2,5 sekundy lub mniej.

Na szybkość wczytywania i renderowania strony internetowej przez przeglądarkę może wpływać wiele czynników, a opóźnienia w ich działaniu mogą mieć znaczący wpływ na LCP.

Rzadko zdarza się, aby szybka poprawa jednego elementu strony spowodowała istotną poprawę wskaźnika LCP. Aby poprawić LCP, musisz przyjrzeć się całemu procesowi wczytywania i upewnić się, że każdy jego etap jest zoptymalizowany.

Interpretowanie danych LCP

Zanim zoptymalizują LCP, deweloperzy powinni sprawdzić, czy w ogóle mają problem z tym wskaźnikiem i jak poważny jest on problem.

LCP można mierzyć za pomocą wielu narzędzi, ale nie wszystkie z nich mierzą go w ten sam sposób. Aby zrozumieć LCP rzeczywistych użytkowników, powinniśmy przyjrzeć się temu, jak czują się oni podczas korzystania z witryny, a nie temu, co pokazuje narzędzie laboratoryjne, takie jak Lighthouse, lub testy lokalne. Te narzędzia laboratoryjne mogą dostarczyć wiele informacji, które pomogą Ci poprawić LCP, ale pamiętaj, że same testy laboratoryjne mogą nie w pełni odzwierciedlać wrażenia użytkowników.

Dane LCP oparte na danych o prawdziwych użytkownikach można uzyskać z instalowanych w witrynie narzędzi Real User Monitoring (RUM) lub z Raportu na temat użytkowania Chrome (CrUX), który zbiera anonimowe dane od prawdziwych użytkowników Chrome na milionach witryn.

Korzystanie z danych LCP w narzędziach deweloperskich w Chrome

Panel wydajności w Narzędziach deweloperskich Chrome pokazuje lokalny czas LCP obok wartości LCP CrUX strony lub pochodzenia w widoku danych na żywo.

LCP na poziomie lokalnym i w polu w panelu Wydajność w Narzędziach deweloperskich w Chrome
Lokalizacja i wartość LCP w panelu Performance (Wydajność) w Narzędziach deweloperskich w Chrome.

Dzięki nakładaniu danych z pól na panelu Wydajność możesz sprawdzić, czy strona ma jakieś problemy z LCP w przypadku rzeczywistych użytkowników, i dostosować ustawienia środowiska lokalnego, aby lepiej odtworzyć te problemy i je debugować.

Korzystanie z danych LCP w raporcie CrUX w PageSpeed Insights

PageSpeed Insights zapewnia dostęp do danych CrUX w sekcji u góry strony o nazwie Dowiedz się, jakie są wrażenia użytkowników. Bardziej szczegółowe dane z testów laboratoryjnych są dostępne w sekcji u dołu strony o nazwie Diagnoza problemów z wydajnością. Jeśli dane CrUX są dostępne w przypadku Twojej witryny, zawsze skup się najpierw na rzeczywistych danych użytkownika.

Dane raportu na temat użytkowania Chrome wyświetlane w PageSpeed Insights
Dane raportu na temat użytkowania Chrome wyświetlane w narzędziu PageSpeed Insights.

Narzędzie PageSpeed Insights wyświetla maksymalnie 4 rodzaje danych CrUX:

  • Dane dotyczące urządzeń mobilnych dotyczące tego adresu URL
  • Dane dotyczące komputera dotyczące tego adresu URL
  • Mobilna transmisja danych w całym Origin
  • Dane Desktop dotyczące całej Origin

Możesz je włączać i wyłączać za pomocą elementów sterujących u góry tej sekcji. Jeśli adres URL nie ma wystarczającej ilości danych, aby wyświetlić je na poziomie adresu URL, ale ma dane źródłowe, narzędzie PageSpeed Insights zawsze wyświetla dane źródłowe.

W przypadku braku danych na poziomie adresu URL narzędzie PageSpeed Insights korzysta z danych na poziomie źródła
Jeśli narzędzie PageSpeed Insights nie ma danych na poziomie adresu URL, pokazuje dane na poziomie źródła.

Wartość LCP dla całej domeny może się znacznie różnić od wartości LCP poszczególnych stron w zależności od tego, jak wczytuje się LCP na danej stronie w porównaniu z innymi stronami w tej domenie. Na liczbę wyświetleń może też wpływać sposób, w jaki użytkownicy docierają do tych stron. Strony główne są zwykle odwiedzane przez nowych użytkowników, dlatego często są wczytywane „na zimno”, bez treści w pamięci podręcznej, co powoduje, że są to często najwolniejsze strony w witrynie.

Analiza 4 różnych kategorii danych z CrUX może pomóc Ci ustalić, czy problem z LCP dotyczy tylko tej strony, czy też jest bardziej ogólnym problemem w całej witrynie. Podobnie może ona pokazywać, które typy urządzeń mają problemy z LCP.

Korzystanie z danych uzupełniających CrUX w PageSpeed Insights

Osoby, które chcą zoptymalizować LCP, powinny też używać wartości pierwszego wyrenderowania treści (FCP)czasu do pierwszego bajta (TTFB), które są dobrymi wskaźnikami diagnostycznymi i mogą dostarczyć cennych informacji o LCP.

TTFB to czas od momentu, gdy użytkownik rozpoczyna nawigację po stronie (np. klika link), do momentu, gdy otrzymane zostaną pierwsze bajty dokumentu HTML. Długi czas TTFB może utrudniać osiągnięcie wartości LCP wynoszącej 2,5 s, a nawet uniemożliwić to.

Długi czas TTFB może być spowodowany wieloma przekierowaniami na serwer, lokalizacją użytkowników daleko od najbliższego serwera witryny, niekorzystnymi warunkami sieci lub brakiem możliwości korzystania z treści w pamięci podręcznej z powodu parametrów zapytania.

Gdy strona zaczyna się renderować, może pojawić się początkowe wyrenderowanie (np. kolor tła), a potem treść (np. nagłówek witryny). Pojawienie się początkowej treści jest mierzone przez wskaźnik FCP. Różnica między FCP a innymi danymi może być bardzo wymowna.

Duża różnica między czasem TTFB a FCP może oznaczać, że przeglądarka musi pobrać wiele komponentów blokujących renderowanie. Może to też oznaczać, że musi wykonać dużo pracy, aby wyrenderować dowolne treści – klasyczny znak, że witryna w dużej mierze polega na renderowaniu po stronie klienta.

Duża różnica między czasem FCP a LCP wskazuje, że zasób LCP jest niedostępny od razu, aby przeglądarka mogła go ustawić jako priorytet (np. tekst lub obrazy zarządzane przez JavaScript, a nie dostępne w początkowym kodzie HTML), lub że przeglądarka wykonuje inne zadania, zanim będzie mogła wyświetlić zawartość LCP.

Korzystanie z danych Lighthouse w PageSpeed Insights

Sekcja Lighthouse w narzędziu PageSpeed Insights zawiera wskazówki dotyczące poprawy LCP, ale najpierw sprawdź, czy LCP jest zgodny z danymi o prawdziwych użytkownikach pochodzącymi z raportu CrUX. Jeśli Lighthouse i CrUX podają sprzeczne informacje, to CrUX prawdopodobnie podaje bardziej dokładny obraz wrażeń użytkowników. Zanim podejmiesz działania, upewnij się, że dane w raporcie CrUX dotyczą Twojej strony, a nie całego źródła.

Jeśli zarówno Lighthouse, jak i CrUX wskazują, że wartości LCP wymagają poprawy, w sekcji Lighthouse znajdziesz cenne wskazówki, jak to zrobić. Użyj filtra LCP, aby wyświetlać tylko audyty dotyczące LCP w ten sposób:

Możliwości i diagnostyka LCP w Lighthouse
Diagnostyka i sugestie Lighthouse dotyczące poprawy LCP.

Oprócz możliwości ulepszenia masz też dostęp do informacji diagnostycznych, które mogą zawierać więcej informacji, które pomogą zdiagnozować problem. Diagnostyka Największe wyrenderowanie treści zawiera przydatne zestawienie różnych wartości czasu, które składają się na LCP:

Etapy LCP w Lighthouse
Zestawienie elementów LCP w Lighthouse.

Teraz przyjrzymy się bliżej tym elementom.

Podział według LCP

Optymalizacja LCP może być bardziej skomplikowanym zadaniem, jeśli narzędzie PageSpeed Insights nie podaje sposobu na poprawę tego wskaźnika. W przypadku skomplikowanych zadań lepiej jest podzielić je na mniejsze, łatwiejsze do wykonania zadania i zająć się nimi oddzielnie.

W tej sekcji przedstawiamy metodę podziału LCP na najważniejsze podelementy, a następnie podajemy konkretne rekomendacje i sprawdzone metody dotyczące optymalizacji każdego z nich.

Większość wczytań stron obejmuje zwykle kilka żądań sieci, ale aby znaleźć możliwości poprawy LCP, na początek powinieneś przyjrzeć się tylko dwóm:

  1. Początkowy dokument HTML
  2. Zasób LCP (jeśli dotyczy)

Inne żądania na stronie mogą wpływać na LCP, ale te 2 żądania, a w szczególności czasy rozpoczęcia i zakończenia zasobu LCP, wskazują, czy Twoja strona jest zoptymalizowana pod kątem LCP.

Aby zidentyfikować zasób LCP, możesz użyć narzędzi dla programistów (takich jak wspomniane wcześniej PageSpeed Insights, Narzędzie deweloperskie w Chrome lub WebPageTest), aby określić element LCP. Możesz tam dopasować adres URL (ponownie, w stosownych przypadkach) wczytany przez element w kaskadówce sieci wszystkich zasobów wczytanych przez stronę.

Na przykład poniższa wizualizacja pokazuje te zasoby wyróżnione na diagramie kaskady sieci z typowego wczytania strony, gdzie element LCP wymaga wysłania żądania obrazu do renderowania.

Sieć kaskadowa z wyróżnionymi zasobami HTML i LCP
Schemat schodkowy pokazujący czas wczytywania kodu HTML strony internetowej i zasobów potrzebnych do spełnienia wymogu LCP.

W przypadku dobrze zoptymalizowanej strony żądanie zasobu LCP powinno się rozpocząć jak najwcześniej, a element LCP powinien zostać wyrenderowany tak szybko, jak to możliwe po zakończeniu wczytywania zasobu LCP. Aby zobrazować, czy dana strona przestrzega tej zasady, możesz podzielić łączny czas LCP na te części:

Czas do pierwszego bajtu (TTFB)
Czas od momentu zainicjowania wczytywania strony przez użytkownika do chwili, gdy przeglądarka otrzyma pierwszy bajt odpowiedzi dokumentu HTML.
Opóźnienie ładowania zasobów
Czas między czasem TTFB a momentem, gdy przeglądarka rozpoczyna wczytywanie zasobu LCP. Jeśli element LCP nie wymaga wczytania zasobów do renderowania (np. jeśli jest to węzeł tekstowy renderowany za pomocą czcionki systemowej), ten czas wynosi 0.
Czas wczytywania zasobu
Czas potrzebny na wczytanie samego zasobu LCP. Jeśli renderowanie elementu LCP nie wymaga załadowania zasobów, ten czas wynosi 0.
Opóźnienie renderowania elementu
Czas od zakończenia wczytywania zasobu LCP do pełnego wyrenderowania elementu LCP.

LCP każdej strony składa się z tych 4 podkategorii. Nie ma między nimi żadnych przerw ani nakładania się. Ich czasy łącznie dają pełny czas LCP.

Wyszczególnienie LCP z 4 podkategoriami
Ten sam diagram kaskadowy z 4 podkategoriami LCP nałożonymi na osi czasu.

Wartość LCP każdej strony może być podzielona na te 4 podelementy. Nie ma między nimi żadnych przerw ani luk. Razem dają one pełny czas LCP.

Podczas optymalizacji LCP warto spróbować zoptymalizować te podelementy osobno. Pamiętaj jednak, że musisz zoptymalizować wszystkie z nich. W niektórych przypadkach optymalizacja zastosowana w jednej części nie poprawi wskaźnika LCP, tylko przesunie zaoszczędzony czas na inną część.

Na przykład w poprzednim łańcuchu sieciowym, jeśli zmniejszysz rozmiar pliku obrazu, bardziej go skompresowując lub przechodząc na bardziej optymalny format (np. AVIF lub WebP), spowoduje to skrócenie czasu wczytywania zasobu, ale nie poprawi to wartości LCP, ponieważ czas ten zostanie po prostu przeniesiony do podelementu opóźnienia renderowania elementu:

Ten sam podział LCP, w którym podkategoria Czas ładowania zasobów została skrócona, ale łączny czas LCP pozostaje taki sam.
Skrócenie czasu ładowania zasobów zwiększa opóźnienie renderowania elementu bez zmniejszania wartości LCP.

Dzieje się tak, ponieważ na tej stronie element LCP jest ukryty, dopóki nie zakończy się wczytywanie kodu JavaScript, a potem wszystko zostaje odsłonięte naraz.

Ten przykład pokazuje, że aby uzyskać najlepsze wyniki LCP, musisz zoptymalizować wszystkie te elementy.

Optymalne czasy przetwarzania podczęści

Aby zoptymalizować poszczególne części LCP, musisz wiedzieć, jak powinna wyglądać ich idealna struktura na dobrze zoptymalizowanej stronie.

Spośród 4 podelementów 2 mają w nazwie słowo „delay” (opóźnienie). To wskazówka, że chcesz, aby te czasy były jak najbliższe zeru. Pozostałe 2 części dotyczą żądań sieci, które z samej swojej natury zajmują trochę czasu.

Część LCP % LCP
Czas do pierwszego bajtu ~40%
Opóźnienie ładowania zasobów <10%
Czas wczytywania zasobu ~40%
Opóźnienie renderowania elementu <10%
RAZEM 100%

Pamiętaj, że te przedziały czasowe są wskazówkami, a nie ścisłymi zasadami. Jeśli czasy LCP na stronach są konsekwentnie w zakresie 2,5 sekundy, nie ma większego znaczenia, jakie są względne proporcje. Jeśli jednak poświęcasz zbyt dużo czasu na etapy „opóźnienia”, trudno będzie Ci stale osiągać docelowy czas 2,5 s.

Warto pamiętać, że czas LCP składa się z tych elementów:

  • Zdecydowana większość czasu LCP powinna być poświęcona na wczytywanie dokumentu HTML i źródła LCP.
  • Każdy moment przed LCP, w którym jeden z tych 2 zasobów nie się wczytuje, to możliwość poprawy.

Jak optymalizować poszczególne części

Teraz, gdy już wiesz, jak poszczególne czasy wczytywania elementów LCP powinny się rozkładać na dobrze zoptymalizowanej stronie, możesz zacząć optymalizować własne strony.

W kolejnych 4 sekcjach znajdziesz zalecenia i sprawdzone metody optymalizacji poszczególnych elementów. Są one prezentowane w kolejności od zmian, które mogą mieć największy wpływ.

1. Wyeliminowanie opóźnienia ładowania zasobów

Celem tego kroku jest jak najszybsze rozpoczęcie wczytywania zasobu LCP. Chociaż teoretycznie zasób może zacząć się wczytywać zaraz po zakończeniu TTFB, w praktyce zawsze występuje pewne opóźnienie, zanim przeglądarki zaczną wczytywać zasoby.

Zasada jest taka, że zasób LCP powinien zacząć się wczytywać w tym samym czasie co pierwszy zasób wczytywany przez stronę. Inaczej mówiąc, jeśli zasób LCP zaczyna się wczytywać później niż pierwszy zasób, istnieje możliwość poprawy.

Schemat kaskadowy sieci przedstawiający zasób LCP zaczynający się po pierwszym zasobie, pokazujący możliwości poprawy
Na tej stronie zasób LCP zaczyna się wczytywać dopiero po arkuszu stylów, który wczytuje się jako pierwszy. Tutaj jest jeszcze miejsce na poprawę.

Ogólnie rzecz biorąc, na szybkość wczytywania zasobu LCP wpływają 2 czynniki:

  • Gdy zostanie odkryty zasób.
  • Priorytet przypisany do zasobu.

Optymalizacja podczas wykrywania zasobu

Aby zasób LCP zaczął się wczytywać jak najwcześniej, musi być on możliwy do wykrycia w pierwotnym dokumencie HTML przez skaner wstępnego wczytania przeglądarki. Na przykład w tych przypadkach przeglądarka może wykryć zasób LCP, skanując odpowiedź dokumentu HTML:

  • Element LCP to element <img>, a jego atrybuty src lub srcset są obecne w początkowym znaczniku HTML.
  • Element LCP wymaga obrazu tła CSS, ale jest on wstępnie wczytywany za pomocą atrybutu <link rel="preload"> w znaczniku HTML (lub za pomocą nagłówka Link).
  • Element LCP to węzeł tekstowy, który wymaga czcionki internetowej do renderowania. W kodzie HTML czcionka jest wczytywana za pomocą atrybutu <link rel="preload"> (lub za pomocą nagłówka Link).

Oto kilka przykładów sytuacji, w których zasób LCP nie może zostać wykryty podczas skanowania odpowiedzi dokumentu HTML:

  • Element LCP to <img>, który jest dynamicznie dodawany do strony za pomocą JavaScriptu.
  • Element LCP jest ładowany z opóźnieniem za pomocą biblioteki JavaScript, która ukrywa atrybuty src lub srcset (często jako data-src lub data-srcset).
  • Element LCP wymaga obrazu tła CSS.

W każdym z tych przypadków przeglądarka musi uruchomić skrypt lub zastosować arkusz stylów (co zwykle wymaga oczekiwania na zakończenie żądań sieciowych), zanim będzie mogła wykryć zasób LCP i rozpocząć jego wczytywanie. To nigdy nie jest optymalne.

Aby wyeliminować niepotrzebne opóźnienia w wczytywaniu zasobów, zasób LCP powinien być możliwy do znalezienia w źródle HTML. W przypadku, gdy zasób jest wywoływany tylko z zewnętrznego pliku CSS lub JavaScript, zasób LCP powinien być wstępnie wczytywany z wysoką priorytetem pobierania, na przykład:

<!-- Load the stylesheet that will reference the LCP image. -->
<link rel="stylesheet" href="/path/to/styles.css">

<!-- Preload the LCP image with a high fetchpriority so it starts loading with the stylesheet. -->
<link rel="preload" fetchpriority="high" as="image" href="/path/to/hero-image.webp" type="image/webp">

optymalizacja priorytetu przypisanego do zasobu;

Nawet jeśli zasób LCP jest możliwy do wykrycia w oznaczeniu HTML, nadal może nie zacząć się wczytywać wcześniej niż pierwszy zasób. Może się tak zdarzyć, jeśli heurystyka priorytetów skanera wstępnego wczytywania przeglądarki nie rozpozna, że zasób jest ważny, lub jeśli uzna, że inne zasoby są ważniejsze.

Możesz na przykład opóźnić obraz LCP, używając kodu HTML, jeśli ustawisz atrybut loading="lazy" w elemencie <img>. Użycie leniwego wczytywania oznacza, że zasób nie zostanie załadowany, dopóki układ nie potwierdzi, że obraz znajduje się w widoku, więc może zacząć się wczytywać później niż normalnie.

Nawet bez leniwego wczytywania obrazy nie są wczytywane przez przeglądarki z najwyższym priorytetem, ponieważ nie są to zasoby blokujące renderowanie. Możesz zasugerować przeglądarce, które zasoby są najważniejsze, używając atrybutu fetchpriority w przypadku zasobów, które mogą korzystać z wyższego priorytetu:

<img fetchpriority="high" src="/path/to/hero-image.webp">

Jeśli uważasz, że element <img> może być elementem LCP strony, warto ustawić dla niego wartość fetchpriority="high". Jeśli jednak ustawisz wysoki priorytet dla więcej niż 1 lub 2 obrazów, nie pomoże to w zmniejszeniu wartości LCP.

Możesz też obniżyć priorytet obrazów, które mogą znajdować się na początku odpowiedzi na dokument, ale nie są widoczne ze względu na stylizację, np. obrazów na slajdach w karuzeli, które nie są widoczne na początku:

<img fetchpriority="low" src="/path/to/carousel-slide-3.webp">

Zmniejszenie priorytetu niektórych zasobów może zapewnić więcej przepustowości zasobom, które jej potrzebują. Zawsze sprawdzaj priorytet zasobów w Narzędziach deweloperskich i testuj zmiany za pomocą narzędzi do testowania w laboratorium i w terenie.

Po optymalizacji priorytetu zasobu LCP i czasu wykrywania zasobów wodospad sieci powinien wyglądać tak (zasób LCP uruchamia się w tym samym czasie co pierwszy zasób):

Schemat kaskady sieciowy przedstawiający zasób LCP, który rozpoczyna się w tym samym momencie co pierwszy zasób
Z tych zasobów LCP zacznie się teraz wczytywać jednocześnie z arkusz stylów.

2. Wyeliminuj opóźnienie renderowania elementu.

Celem tego kroku jest zapewnienie, aby element LCP mógł zostać wyrenderowany natychmiast po zakończeniu wczytywania jego zasobu, niezależnie od tego, kiedy to nastąpi.

Głównym powodem, dla którego element LCP nie może zostać wyrenderowany natychmiast po zakończeniu wczytywania jego zasobu, jest to, że renderowanie jest blokowane z jakiegoś innego powodu:

  • Renderowanie całej strony jest zablokowane z powodu wczytywania się arkuszy stylów lub skryptów synchronicznych w elementach <head>.
  • Zasób LCP został załadowany, ale element LCP nie został jeszcze dodany do DOM (czeka na załadowanie kodu JavaScript).
  • Element jest ukryty przez inny kod, np. bibliotekę testów A/B, która wciąż określa, w jakim eksperymencie powinien uczestniczyć użytkownik.
  • Wątek główny jest zablokowany z powodu długich zadań, a renderowanie musi poczekać na ich zakończenie.

W następnych sekcjach wyjaśniamy, jak rozwiązać problemy związane z najczęstszymi przyczynami opóźnień w renderowaniu elementów.

Ogranicz lub usuń czcionki w plikach CSS, które blokują renderowanie

Arkusze stylów wczytane z otagowania HTML będą blokować renderowanie wszystkich treści, które się za nimi znajdują. Jest to dobre, ponieważ zazwyczaj nie chcesz renderować niestylizowanego kodu HTML. Jeśli jednak arkusz stylów jest tak duży, że jego wczytanie zajmuje znacznie więcej czasu niż zasób LCP, uniemożliwi to renderowanie elementu LCP, nawet po zakończeniu wczytywania zasobu, jak w tym przykładzie:

Diagram siatki sieci pokazujący duży plik CSS blokujący renderowanie elementu LCP, ponieważ jego wczytanie zajmuje więcej czasu niż zasób LCP
Obraz i arkusz stylów zaczynają się wczytywać w tym samym momencie, ale obraz nie może zostać wyrenderowany, dopóki arkusz stylów nie będzie gotowy.

Aby rozwiązać ten problem, możesz:

  • wstawić arkusz stylów bezpośrednio w pliku HTML, aby uniknąć dodatkowego żądania sieciowego;
  • zmniejszyć rozmiar arkusza stylów.

Wstawianie arkusza stylów jest zalecane tylko wtedy, gdy arkusz jest mały, ponieważ wstawiane treści w kodzie HTML nie mogą korzystać z pamięci podręcznej podczas kolejnych wczytywań strony. Jeśli arkusz stylów jest tak duży, że jego wczytanie zajmuje więcej czasu niż zasób LCP, prawdopodobnie nie nadaje się do wstawienia w kod HTML.

W większości przypadków najlepszym sposobem na upewnienie się, że arkusz stylów nie blokuje renderowania elementu LCP, jest zmniejszenie jego rozmiaru, tak aby był mniejszy niż zasób LCP. Dzięki temu nie będzie ona wąskim gardłem w przypadku większości wizyt.

Oto kilka zaleceń dotyczących zmniejszania rozmiaru arkusza stylów:

Odkładanie lub umieszczanie w kodze źródłowym kodu JavaScript blokującego renderowanie

Dodawanie skryptów synchronicznych (bez atrybutów async lub defer) do <head> stron jest prawie nigdy niepotrzebne i prawie zawsze ma negatywny wpływ na wydajność.

Jeśli kod JavaScript musi być wykonywany jak najwcześniej podczas wczytywania strony, najlepiej umieścić go w kodze HTML, aby nie opóźniać renderowania przez oczekiwanie na inne żądanie sieci. Podobnie jak w przypadku arkuszy stylów, skrypty powinny być wstawiane w postaci kodu tylko wtedy, gdy są bardzo małe.

Nie
<head>
 
<script src="/path/to/main.js"></script>
</head>
Tak
<head>
 
<script>
   
// Inline script contents directly in the HTML.
   
// IMPORTANT: only do this for very small scripts.
 
</script>
</head>

Korzystanie z renderowania po stronie serwera

Renderowanie po stronie serwera (SSR) to proces wykonywania logiki aplikacji po stronie klienta na serwerze i odpowiedzi na żądania dotyczące dokumentu HTML z pełnym znacznikiem HTML.

Z punktu widzenia optymalizacji LCP SSR ma 2 główne zalety:

  • Twoje zasoby obrazów będą dostępne w źródle HTML (jak opisano w kroku 1).
  • Treści strony nie będą wymagać dodatkowych żądań JavaScript, aby można je było renderować.

Główną wadą SSR jest to, że wymaga dodatkowego czasu przetwarzania na serwerze, co może spowolnić czas TTFB. Zwykle jednak warto, ponieważ czas przetwarzania na serwerze jest pod Twoją kontrolą, a możliwości sieci i urządzeń użytkowników nie.

Opcja podobna do SSR to generowanie witryn statycznych (SSG) lub renderowanie wstępne. Jest to proces generowania stron HTML na etapie kompilacji, a nie na żądanie. Jeśli w Twojej architekturze jest możliwe prerenderowanie, jest to zazwyczaj lepszy wybór pod kątem wydajności.

Dzielenie długich zadań

Nawet jeśli zastosujesz się do wcześniejszych wskazówek i Twój kod JavaScript nie będzie blokować renderowania ani nie będzie odpowiedzialny za renderowanie elementów, może on opóźniać LCP.

Najczęstszą przyczyną jest wczytywanie przez strony dużych plików JavaScriptu, które muszą zostać przeanalizowane i wykonane w głównym wątku przeglądarki. Oznacza to, że nawet jeśli zasób obrazu został całkowicie pobrany, może on nadal czekać na zakończenie wykonania niezwiązanego skryptu, zanim zostanie poddany renderowaniu.

Obecnie wszystkie przeglądarki renderują obrazy w głównym wątku, co oznacza, że wszystko, co blokuje ten wątek, może też spowodować niepotrzebne opóźnienie renderowania elementu.

3. Skrócenie czasu wczytywania zasobów

Celem tego kroku jest skrócenie czasu przesyłania bajtów zasobu przez sieć na urządzenie użytkownika. Ogólnie można to zrobić na 4 sposoby:

  • Zmniejsz rozmiar zasobu.
  • Zmniejsz odległość, jaką ma pokonać zasób.
  • zmniejszenie rywalizacji o przepustowość sieci;
  • całkowicie wyeliminować czas sieci;

Zmniejsz rozmiar zasobu

Zasób LCP strony (jeśli taki istnieje) to obraz lub czcionka internetowa. W tych przewodnikach znajdziesz szczegółowe informacje o tym, jak zmniejszyć rozmiar obu tych plików:

zmniejszyć odległość, jaką ma pokonać zasób;

Oprócz zmniejszenia rozmiaru zasobu możesz też skrócić czas wczytywania, umieszczając serwery jak najbliżej użytkowników pod względem geograficznym. Najlepszym sposobem jest użycie sieci dostarczania treści (CDN).

CDN obrazów są szczególnie przydatne, ponieważ nie tylko zmniejszają odległość, jaką musi pokonać zasób, ale także ogólnie zmniejszają jego rozmiar, automatycznie stosując w Twoim imieniu wszystkie wcześniejsze rekomendacje dotyczące zmniejszania rozmiaru.

zmniejszenie rywalizacji o przepustowość sieci;

Nawet jeśli zmniejszysz rozmiar zasobu i odległość, jaką musi pokonać, wczytywanie zasobu może potrwać długo, jeśli wczytujesz wiele innych zasobów w tym samym czasie. Ten problem nazywamy konkurencją sieciową.

Jeśli nadasz zasobowi LCP wysoki priorytet fetchpriorityzaczniesz wczytywać go tak szybko, jak to możliwe, przeglądarka zrobi wszystko, co możliwe, aby zasoby o niższym priorytecie nie mogły z nim konkurować. Jeśli jednak wczytujesz wiele zasobów o wysokiej wartości fetchpriority lub po prostu wczytujesz dużo zasobów, może to wpłynąć na szybkość wczytywania zasobu LCP.

całkowicie wyeliminować czas sieci;

Najlepszym sposobem na skrócenie czasu wczytywania zasobów jest całkowite wyeliminowanie sieci z procesu. Jeśli zasoby są dostarczane zgodnie z skuteczną zasadą kontroli pamięci podręcznej, użytkownicy, którzy po raz drugi poproszą o te zasoby, otrzymają je z pamięci podręcznej. W ten sposób czas wczytywania zasobów będzie praktycznie zerowy.

Jeśli zasób LCP to czcionka internetowa, oprócz zmniejszenia rozmiaru czcionki internetowej zastanów się, czy nie trzeba zablokować renderowania podczas wczytywania czcionki internetowej. Jeśli wartość atrybutu font-display jest inna niż auto lub block, tekst będzie zawsze widoczny podczas wczytywania, a LCP nie będzie blokowane w dodatkowym żądaniu sieci.

Jeśli zasób LCP jest mały, warto umieścić go w sposób inline jako adres URL danych, co pozwoli też uniknąć dodatkowego żądania sieci. Używanie adresów URL danych wymaga jednak zastrzeżeń, ponieważ zasoby nie mogą być przechowywane w pamięci podręcznej, a w niektórych przypadkach może to spowodować dłuższe opóźnienia w renderowaniu z powodu dodatkowego kosztu dekodowania.

4. Skrócenie czasu do pierwszego bajtu

Celem tego kroku jest jak najszybsze przesłanie początkowego kodu HTML. Ten krok jest wymieniony na końcu, ponieważ często deweloperzy mają nad nim najmniejszą kontrolę. Jest to jednak też jeden z najważniejszych kroków, ponieważ ma bezpośredni wpływ na wszystkie kolejne kroki. Dopóki backend nie prześle pierwszego bajta treści, nic nie może się dziać po stronie front-endu. Dlatego wszystko, co możesz zrobić, aby przyspieszyć TTFB, poprawi też wszystkie inne wskaźniki wczytywania.

Częstą przyczyną długiego czasu TTFB w przypadku szybkiej witryny jest to, że użytkownicy docierają do niej przez wiele przekierowań, np. z reklam lub linków skróconych. Zawsze minimalizuj liczbę przekierowań, które musi przejść użytkownik.

Inną częstą przyczyną jest sytuacja, gdy nie można użyć treści z pamięci podręcznej z serwera peryferyjnego CDN, a wszystkie żądania muszą być kierowane z powrotem do serwera źródłowego. Może się tak zdarzyć, jeśli unikalne parametry adresu URL są używane przez użytkowników do celów analitycznych, nawet jeśli nie powodują one wyświetlenia innej strony.

Szczegółowe wskazówki dotyczące optymalizacji czasu oczekiwania na odpowiedź znajdziesz w przewodniku po optymalizacji czasu oczekiwania na odpowiedź.

Monitorowanie podziału LCP w JavaScript

Informacje o czasie dla wszystkich wcześniej omówionych podelementów LCP są dostępne w JavaScript za pomocą kombinacji tych interfejsów API dotyczących wydajności:

Obliczanie tych wartości w JavaScriptzie ma tę zaletę, że możesz wysyłać je do dostawcy usługi analitycznej lub rejestrować w narzędziach dla programistów, aby ułatwić debugowanie i optymalizowanie.

Na przykład na poniższym zrzucie ekranu użyto metody performance.measure() z interfejsu User Timing API, aby dodać paski do ścieżki Czas na panelu Wydajność w Narzędziach deweloperskich w Chrome.

Dane User Timing dotyczące podkategorii LCP zwizualizowane w Narzędziach deweloperskich w Chrome
Na ścieżce Czasy wyświetlane są harmonogramy dla podkategorii LCP.

Wizualizacje na ścieżce Czas trwania są szczególnie przydatne, gdy oglądasz je razem ze ścieżkami SiećGłówny wątek, ponieważ dzięki temu możesz od razu zobaczyć, co jeszcze dzieje się na stronie w tych przedziałach czasu.

Oprócz wizualizacji części składowych LCP w ścieżce Czas możesz też użyć JavaScriptu do obliczenia, jaki procent czasu zajmuje każda z nich w stosunku do całkowitego czasu LCP. Dzięki tym informacjom możesz sprawdzić, czy Twoje strony spełniają zalecane odsetki opisane wcześniej.

Ten zrzut ekranu pokazuje przykład, w którym na konsoli rejestrowany jest łączny czas trwania poszczególnych części LCP oraz ich procentowy udział w całości LCP.

Czasy podkategorii LCP oraz ich odsetek w LCP są drukowane w konsoli.
Czasy ładowania i odsetek użytkowników w podkategoriach LCP.

Obie te wizualizacje zostały utworzone za pomocą tego kodu:

const LCP_SUB_PARTS = [
 
'Time to first byte',
 
'Resource load delay',
 
'Resource load duration',
 
'Element render delay',
];

new PerformanceObserver((list) => {
 
const lcpEntry = list.getEntries().at(-1);
 
const navEntry = performance.getEntriesByType('navigation')[0];
 
const lcpResEntry = performance
   
.getEntriesByType('resource')
   
.filter((e) => e.name === lcpEntry.url)[0];

 
// Ignore LCP entries that aren't images to reduce DevTools noise.
 
// Comment this line out if you want to include text entries.
 
if (!lcpEntry.url) return;

 
// Compute the start and end times of each LCP sub-part.
 
// WARNING! If your LCP resource is loaded cross-origin, make sure to add
 
// the `Timing-Allow-Origin` (TAO) header to get the most accurate results.
 
const ttfb = navEntry.responseStart;
 
const lcpRequestStart = Math.max(
    ttfb
,
   
// Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
    lcpResEntry
? lcpResEntry.requestStart || lcpResEntry.startTime : 0
 
);
 
const lcpResponseEnd = Math.max(
    lcpRequestStart
,
    lcpResEntry
? lcpResEntry.responseEnd : 0
 
);
 
const lcpRenderTime = Math.max(
    lcpResponseEnd
,
   
// Use LCP startTime (the final LCP time) because there are sometimes
   
// slight differences between loadTime/renderTime and startTime
   
// due to rounding precision.
    lcpEntry
? lcpEntry.startTime : 0
 
);

 
// Clear previous measures before making new ones.
 
// Note: due to a bug, this doesn't work in Chrome DevTools.
  LCP_SUB_PARTS
.forEach((part) => performance.clearMeasures(part));

 
// Create measures for each LCP sub-part for easier
 
// visualization in the Chrome DevTools Performance panel.
 
const lcpSubPartMeasures = [
    performance
.measure(LCP_SUB_PARTS[0], {
      start
: 0,
      end
: ttfb,
   
}),
    performance
.measure(LCP_SUB_PARTS[1], {
      start
: ttfb,
      end
: lcpRequestStart,
   
}),
    performance
.measure(LCP_SUB_PARTS[2], {
      start
: lcpRequestStart,
      end
: lcpResponseEnd,
   
}),
    performance
.measure(LCP_SUB_PARTS[3], {
      start
: lcpResponseEnd,
      end
: lcpRenderTime,
   
}),
 
];

 
// Log helpful debug information to the console.
  console
.log('LCP value: ', lcpRenderTime);
  console
.log('LCP element: ', lcpEntry.element, lcpEntry.url);
  console
.table(
    lcpSubPartMeasures
.map((measure) => ({
     
'LCP sub-part': measure.name,
     
'Time (ms)': measure.duration,
     
'% of LCP': `${
       
Math.round((1000 * measure.duration) / lcpRenderTime) / 10
     
}%`,
   
}))
 
);
}).observe({type: 'largest-contentful-paint', buffered: true});

Możesz użyć tego kodu bez zmian do debugowania lokalnego lub zmodyfikować go, aby wysyłać te dane do dostawcy usług analitycznych. Dzięki temu lepiej poznasz podział LCP na stronach w przypadku rzeczywistych użytkowników.

Podsumowanie

LCP jest złożonym procesem, a jego czas trwania zależy od wielu czynników. Jeśli jednak weźmiesz pod uwagę, że optymalizacja LCP polega przede wszystkim na optymalizacji wczytywania zasobu LCP, może to znacznie uprościć sprawę.

Ogólnie rzecz biorąc, optymalizację LCP można podsumować w 4 kroki:

  1. Upewnij się, że zasób LCP zaczyna się ładować jak najwcześniej.
  2. Upewnij się, że element LCP może zostać wyświetlony, gdy tylko jego zasób zostanie wczytany.
  3. Zmniejsz czas wczytywania zasobu LCP tak bardzo, jak to możliwe, bez obniżania jakości.
  4. Prześlij jak najszybciej początkowy dokument HTML.

Jeśli możesz wykonać te czynności na swoich stronach, możesz mieć pewność, że zapewniasz użytkownikom optymalne wczytywanie, co powinno być widoczne w rzeczywistych wynikach LCP.