Przewodnik po korzystaniu z WebPageTest do wykrywania 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);
Wynikiem jest tablica przesunięć układu, które nie są poprzedzone zdarzeniami wejścia:
[
{
"name": "",
"entryType": "layout-shift",
"startTime": 210.78500000294298,
"duration": 0,
"value": 0.0001045969445437389,
"hadRecentInput": false,
"lastInputTime": 0
}
]
W tym przykładzie wystąpiła pojedyncza bardzo niewielka zmiana o 0,01% w miejscu 210 ms.
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 API niestabilności układu jest domyślnie włączony, więc możesz uruchomić ten fragment kodu JS w dowolnej witrynie w Chrome 77 i od razu uzyskać wyniki. W WebPageTest możesz używać domyślnej przeglądarki Chrome i nie musisz się martwić flagami wiersza poleceń ani używaniem 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.
Do testu użyję witryny ismyhostfastyet.com, którą stworzyłem, aby porównać rzeczywistą szybkość wczytywania hostów internetowych.
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, w czasie 3087 ms nastąpiło jedno przesunięcie układu o 34,2%. Aby ułatwić identyfikację winowajcy, użyjemy widoku paska filmowego w WebPageTest.
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.
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 ją wypełnić 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 on znak „█”, który powtarza się losową liczbę razy, aby utworzyć wizualne substytuty tekstu, oraz losowo wygenerowaną dystrybucję 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. Ich celem jest zapewnienie użytkownikom, że treści są dostępne i strona nie jest uszkodzona.
Oto jak wyglądają pola zastępcze podczas wczytywania danych JSON:
Rozwiązanie problemu z czcionką internetową jest znacznie łatwiejsze. Ponieważ witryna korzysta z czcionek Google, w żądaniu CSS wystarczy przekazać tylko 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:
[
{
"name": "",
"entryType": "layout-shift",
"startTime": 3070.9349999997357,
"duration": 0,
"value": 0.000050272187989256116,
"hadRecentInput": false,
"lastInputTime": 0
}
]
Według wskaźnika niestandardowego przesunięcie układu nadal występuje po 3071 ms (około tyle samo co wcześniej), ale jego waga jest znacznie mniejsza: 0,005%. Mogę się z tym pogodzić.
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
Przydatne jest przetestowanie strony w usłudze WebPageTest przed optymalizacją i po niej, aby zobaczyć 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ących 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 Twoja konkurencja) sobie radzisz, a także zbadać stan niestabilności układu w internecie.