Naprawianie niestabilności układu

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

W poprzednim poście pisałem o mierzeniu skumulowanego przesunięcia układu (CLS) w WebPageTest. CLS to zsumowanie wszystkich przesunięć układu, więc w tym poście uznałem, że warto przyjrzeć się bliżej poszczególnym przesunięciom układu na stronie, aby zrozumieć, co może być przyczyną niestabilności, i spróbować rozwiązać problem.

Pomiar przesunięć układu

Za pomocą interfejsu Layout Instability API możemy uzyskać 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);

Powoduje to tablicę przesunięć układu, których nie poprzedzają zdarzenia wejściowe:

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

W tym przykładzie przy 210 ms wystąpiła mała zmiana o 0,01%.

Znajomość czasu i zasięgu zmiany pomaga określić, co mogło być jej przyczyną. Wróćmy do WebPageTest, aby przeprowadzić więcej testów w środowisku laboratoryjnym.

Pomiar przesunięć układu w WebPageTest

Podobnie jak w przypadku pomiaru CLS w usłudze WebPageTest, pomiar poszczególnych przesunięć układu wymaga danych niestandardowych. Na szczęście teraz, gdy Chrome 77 jest stabilny, proces ten jest łatwiejszy. Interfejs Layout Instability API jest domyślnie włączony, więc możesz od razu uruchomić ten fragment kodu JS w dowolnej witrynie w Chrome. W WebPageTest możesz używać domyślnej przeglądarki Chrome i nie musisz się martwić o flagi wiersza poleceń ani używanie Canary.

Zmodyfikujmy teraz skrypt, aby wygenerować dane niestandardowe dla 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 jest reprezentowana przez tablicę JSON, a nie przez samą tablicę. Dzieje się tak, ponieważ dane niestandardowe mogą generować tylko podstawowe typy danych, takie jak ciągi znaków lub liczby.

Witryna, której użyję w tym teście, to ismyhostfastyet.com. Stworzona przeze mnie witryna umożliwia porównanie rzeczywistej wydajności ładowania stron u dostawców hostingu witryn.

Identyfikowanie przyczyn niestabilności układu

W sekcji Wyniki widać, że dane niestandardowe LayoutShifts mają tę wartość:

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

Podsumowując, przy 3087 ms zachodzi pojedyncze przesunięcie układu o 34,2%. Aby ułatwić identyfikację winowajcy, użyjemy widoku paska filmowego w WebPageTest.

2 komórki na osi czasu, w których znajdują się zrzuty ekranu przedstawiające stan przed i po zmianie układu.
2 komórki na pasku zdjęć zawierające zrzuty ekranu przed i po zmianie układu.

Przewinięcie do 3 sekundowego znacznika na osi czasu pokazuje, co dokładnie było przyczyną zmiany układu o 34%: kolorowa tabela. Witryna asynchronicznie pobiera plik JSON, a potem renderuje go w tabeli. Tabela jest początkowo pusta, więc oczekiwanie na jej wypełnienie po załadowaniu wyników powoduje przesunięcie.

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

To nie wszystko. Gdy strona jest wizualnie kompletna (po około 4,3 sekundach), widzimy, że <h1> strony „Mój host jest już szybki?” pojawia się znikąd. Dzieje się tak, ponieważ witryna używa czcionek internetowych i nie podjęto żadnych działań w celu optymalizacji renderowania. Nie wygląda na to, aby układ się zmieniał, ale i tak użytkownicy muszą czekać tak długo, aby przeczytać tytuł.

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

Wiemy już, że tabela generowana asynchronicznie powoduje przesunięcie o 1/3 widoku, więc czas to naprawić. Treści tabeli nie są znane, dopóki wyniki JSON nie zostaną faktycznie załadowane, ale możemy wypełnić ją danymi zastępczymi, aby układ był stosunkowo stabilny podczas renderowania DOM.

Oto kod służący 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'));

Dane zastępcze są generowane losowo przed posortowaniem. Zawiera też znak „█” powtórzony losowo określoną liczbę razy, co pozwala utworzyć wizualne obiekty zastępcze dla tekstu oraz losowo wygenerowany rozkład 3 głównych wartości. Dodałem też kilka stylów, aby odbarwić całą tabelę, co ma wskazywać, że dane nie są jeszcze w pełni załadowane.

Wygląd obiektów zastępczych nie ma znaczenia dla stabilności układu. Symbole zastępcze służą zapewnieniu użytkownikom, że treści pochodzą, a strona nie działa.

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

Tabela danych jest renderowana z danymi zastępczymi.
Tabela danych jest renderowana z danymi zastępczymi.

Rozwiązanie problemu z czcionką internetową jest znacznie łatwiejsze. Ponieważ witryna korzysta z czcionek Google, musimy tylko przekazać w żądaniu CSS właściwość display=swap. To wszystko. Interfejs Fonts API doda styl font-display: swap w deklaracji czcionki, umożliwiając przeglądarce natychmiastowe renderowanie tekstu w czcionce zastępczej. Oto odpowiedni znacznik z wprowadzoną poprawką:

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

Sprawdzanie optymalizacji

Po ponownym przetestowaniu strony za pomocą WebPageTest możemy wygenerować porównanie stanu strony przed i po zmianach, aby zwizualizować różnicę i pomiar nowego stopnia niestabilności układu:

Pasek filmowy WebPageTest pokazujący wczytywanie obu witryn obok siebie z optymalizacją układu i bez niej.
Film w WebPageTest pokazujący wczytywanie obu witryn 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 przesunięcie układu nadal występuje o 3071 ms (mniej więcej w tym samym czasie co wcześniej), ale jego wagę jest znacznie mniejsza: 0,005%. Mogę z tym żyć.

Z paska filmowego widać też, że czcionka <h1> natychmiast przechodzi na czcionkę systemową, co pozwala użytkownikom szybciej ją odczytać.

Podsumowanie

W przypadku złożonych witryn prawdopodobnie wystąpi znacznie więcej zmian układu niż w tym przykładzie, ale proces naprawczy jest taki sam: dodaj do WebPageTest dane o niestabilności układu, porównaj wyniki z wizualnym paskiem filmowym, aby zidentyfikować problemy, i wprowadź poprawki za pomocą placeholderów, aby zarezerwować miejsce na ekranie.

(Jeszcze jedna rzecz) Pomiar niestabilności układu przez rzeczywistych użytkowników

Warto uruchomić WebPageTest przed optymalizacją strony i po niej, aby sprawdzić poprawę wskaźnika, ale najważniejsze jest to, aby wrażenia użytkownika rzeczywiście się poprawiły. Czy nie dlatego staramy się ulepszać naszą stronę?

Dlatego warto zacząć mierzyć niestabilność układu w przypadku rzeczywistych użytkowników wraz z naszym tradycyjnym zestawem danych o wydajności witryny. Jest to kluczowy element pętli informacji zwrotnych dotyczącej optymalizacji, ponieważ dane z pola informują nas, gdzie występują problemy i czy nasze poprawki przyniosły pozytywne rezultaty.

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 kumulatywnej zmianie układu na podstawie doświadczeń prawdziwych użytkowników na milionach witryn. Dzięki niemu możesz sprawdzić, jak Ty (lub Twoi konkurenci) się spisujesz, a także zbadać stan niestabilności układu w internecie.