Naprawianie niestabilności układu

Przewodnik po korzystaniu z WebPageTest do identyfikowania i rozwiązywania problemów z niestabilnością układu.

We wcześniejszym poście piszemy o pomiarze skumulowanego przesunięcia układu (CLS) w narzędziu WebPageTest. CLS to zbiór wszystkich przesunięć układu, więc w tym poście warto dokładniej przeanalizować każde przesunięcie układu na stronie, aby spróbować zrozumieć, co może powodować niestabilność, i spróbować rozwiązać problemy.

Pomiar przesunięć układu

Za pomocą interfejsu Layout Instability API możemy pobrać listę wszystkich zdarzeń przesunięcia układu na stronie:

new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(list.getEntries().filter(entry => !entry.hadRecentInput));
  }).observe({type: "layout-shift", buffered: true});
}).then(console.log);

Generuje to tablicę przesunięć układu, które nie są poprzedzone zdarzeniami związanymi z danymi wejściowymi:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 210.78500000294298,
    "duration": 0,
    "value": 0.0001045969445437389,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

W tym przykładzie wystąpiło jedno bardzo małe przesunięcie o 0,01% w czasie 210 ms.

Znajomość czasu i wagi zmiany może pomóc w ustaleniu, co mogło spowodować tę zmianę. Wróćmy do środowiska WebPageTest, w którym znajdziesz środowisko modułu umożliwiające przeprowadzenie dodatkowych testów.

Pomiar przesunięć układu w WebPageTest

Podobnie jak w przypadku pomiaru CLS w WebPageTest, pomiar poszczególnych przesunięcia układu wymaga danych niestandardowych. Na szczęście ten proces jest łatwiejszy, ponieważ Chrome 77 jest stabilny. Interfejs Układ Instability API jest domyślnie włączony, więc możesz uruchomić ten fragment kodu JS w dowolnej witrynie w Chrome 77 i uzyskać natychmiastowe wyniki. W WebPageTest możesz używać domyślnej przeglądarki Chrome, więc nie musisz martwić się o flagi wiersza poleceń ani korzystanie z wersji Canary.

Zmodyfikujmy ten skrypt, aby wygenerować niestandardowe dane dla funkcji WebPageTest:

[LayoutShifts]
return new Promise(resolve => {
  new PerformanceObserver(list => {
    resolve(JSON.stringify(list.getEntries().filter(entry => !entry.hadRecentInput)));
  }).observe({type: "layout-shift", buffered: true});
});

Obietnica w tym skrypcie odnosi się do tablicy, która jest reprezentowana w formacie JSON, a nie samej tablicy. Dzieje się tak, ponieważ dane niestandardowe mogą generować tylko podstawowe typy danych, takie jak ciągi znaków czy liczby.

Wykorzystam witrynę do testowania: ismyhostfastyet.com. Utworzyłam ją, aby porównywać rzeczywistą szybkość wczytywania stron internetowych.

Identyfikowanie przyczyn niestabilności układu

W wynikach widać, że dane niestandardowe LayoutShifts mają taką wartość:

[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3087.2349999990547,
    "duration": 0,
    "value": 0.3422101449275362,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

Podsumowując, w czasie 3087 ms następuje jedno przesunięcie układu o 34,2%. Aby zidentyfikować przyczynę problemu, użyjmy widoku paska zdjęć w narzędziu WebPageTest.

Dwie komórki na pasku zdjęć, na których widać zrzuty ekranu przed przesunięciem układu i po nim.
Dwie komórki na pasku zdjęć ze zrzutami ekranu przed przesunięciem układu i po nim.

Po przewinięciu do ok. 3 sekund na pasku zdjęć widać, co jest dokładnie przyczyną przesunięcia układu 34%: kolorowy stół. Witryna asynchronicznie pobiera plik JSON, a następnie renderuje go w tabeli. Początkowo tabela jest pusta, więc przesunięcie jest spowodowane oczekiwaniem na zapełnienie tabeli po wczytaniu wyników.

Nagłówek czcionki internetowej, który pojawia się znikąd.
Nagłówek czcionki internetowej, który pojawia się znikąd.

To jednak nie wszystko. Gdy strona będzie gotowa w ciągu ok.4,3 sekundy, widać, że pole <h1> strony „Czy mój host jest już szybkie?” pojawia się znikąd. Wynika to z faktu, że witryna korzysta z czcionki internetowej i nie podjęła żadnych kroków w celu optymalizacji renderowania. W rzeczywistości układ nie zmienił się w tym przypadku, ale i tak zniechęcało się użytkowników, którzy zbyt długo musieli czekać na tytuł.

Rozwiązywanie problemów z niestabilnością układu

Skoro wiemy już, że asynchronicznie generowana tabela powoduje przesuwanie się jednej trzeciej widocznego obszaru, nadszedł czas, aby to naprawić. Zawartość tabeli nie znamy, dopóki wyniki JSON nie zostaną wczytane, ale nadal możemy wypełnić ją danymi zastępczymi, dzięki czemu układ będzie względnie stabilny podczas renderowania DOM.

Oto kod do generowania danych zastępczych:

function getRandomFiller(maxLength) {
  var filler = '█';
  var len = Math.ceil(Math.random() * maxLength);
  return new Array(len).fill(filler).join('');
}

function getRandomDistribution() {
  var fast = Math.random();
  var avg = (1 - fast) * Math.random();
  var slow = 1 - (fast + avg);
  return [fast, avg, slow];
}

// Temporary placeholder data.
window.data = [];
for (var i = 0; i < 36; i++) {
  var [fast, avg, slow] = getRandomDistribution();
  window.data.push({
    platform: getRandomFiller(10),
    client: getRandomFiller(5),
    n: getRandomFiller(1),
    fast,
    avg,
    slow
  });
}
updateResultsTable(sortResults(window.data, 'fast'));

Przed sortowaniem dane zastępcze są generowane losowo. Obejmuje to znak „█” powtórzony losową liczbę razy w celu utworzenia wizualnych obiektów zastępczych tekstu oraz losowo wygenerowany rozkład 3 wartości głównych. Dodałem też kilka stylów, aby zmniejszyć nasycenie wszystkich kolorów tabeli i było jasne, że dane nie są jeszcze w pełni wczytane.

Wygląd używanych obiektów zastępczych nie ma wpływu na stabilność układu. Symbole zastępcze mają na celu zapewnienie użytkowników, że treść pochodzi, a strona nie jest uszkodzony.

Tak wyglądają symbole zastępcze podczas wczytywania danych JSON:

Tabela danych jest renderowana na podstawie danych zastępczych.
Tabela danych jest renderowana z danymi zastępczymi.

Problem z czcionkami internetowymi jest znacznie łatwiejszy. Strona korzysta z Google Fonts, więc musimy tylko przekazać właściwość display=swap w żądaniu CSS. To wszystko. Interfejs Fonts API doda do deklaracji czcionki styl font-display: swap, co umożliwi przeglądarce natychmiastowe renderowanie tekstu w czcionce zastępczej. Oto odpowiadające mu znaczniki z uwzględnioną poprawką:

<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">

Sprawdzanie optymalizacji

Po ponownym uruchomieniu strony za pomocą narzędzia WebPageTest możemy wygenerować porównanie przed i po, aby zwizualizować różnice i zmierzyć nowy stopień niestabilności układu:

Seria zdjęć WebPageTest przedstawiająca obie witryny wczytujące się obok siebie z optymalizacją układu i bez niej.
Seria filmów WebPageTest przedstawiająca obie strony wczytujące się obok siebie z optymalizacją układu i bez niej.
[
  {
    "name": "",
    "entryType": "layout-shift",
    "startTime": 3070.9349999997357,
    "duration": 0,
    "value": 0.000050272187989256116,
    "hadRecentInput": false,
    "lastInputTime": 0
  }
]

Zgodnie z danymi niestandardowymi zmiana układu nadal występuje 3071 ms (mniej więcej w tym samym czasie co wcześniej), ale jest znacznie mniejsza i wynosi 0,005%. Dam sobie radę z tym.

Z paska filmu łatwo widać też, że czcionka <h1> natychmiast wraca do czcionki systemowej, dzięki czemu użytkownicy mogą ją szybciej przeczytać.

Podsumowanie

W przypadku złożonych witryn może wystąpić o wiele więcej przesunięć układu niż w tym przykładzie, ale proces reagowania jest taki sam: dodaj do WebPageTest wskaźniki niestabilności układu, porównaj wyniki z paskiem wczytywania obrazu, aby zidentyfikować problemy i zaimplementuj poprawki za pomocą obiektów zastępczych, aby zarezerwować miejsce na ekranie.

(Jeszcze jedna sprawa) Pomiar niestabilności układu, który ma miejsce w przypadku rzeczywistych użytkowników.

Dobrze jest mieć możliwość przeprowadzenia WebPageTest na stronie przed optymalizacją i po niej i zauważenie poprawy niektórych danych. Najważniejsze jest jednak to, że wrażenia użytkowników są coraz lepsze. Czy nie dlatego od razu staramy się ulepszać tę witrynę?

Bardzo dobrze byłoby więc zacząć mierzyć niestabilność układu stron rzeczywistych użytkowników przy jednoczesnym korzystaniu z tradycyjnych danych o wydajności witryn. Jest to kluczowy element pętli informacji zwrotnych o optymalizacji, ponieważ dzięki danym z tych pól dowiemy się, gdzie są problemy i czy wprowadzone poprawki przyniosły pozytywne efekty.

Oprócz zbierania własnych danych o niestabilności układu zapoznaj się z Raportem na temat użytkowania Chrome, który zawiera dane o skumulowanym zmianie układu na podstawie doświadczeń użytkowników na milionach stron internetowych. Dzięki temu możesz dowiedzieć się, jak sobie radzisz (lub jak wypadasz na tle konkurencji). Możesz też użyć tych danych, aby poznać stan niestabilności układu w internecie.