Przewodnik po korzystaniu z WebPageTest do identyfikowania i rozwiązywania problemów z niestabilnością układu.
W jednym z poprzednich postów pisałem o mierzeniu skumulowanego przesunięcia układu (CLS) w WebPageTest. CLS to suma wszystkich przesunięć układu, więc w tym poście postanowiłem przyjrzeć się bliżej każdemu z nich na stronie, aby zrozumieć, co może powodować niestabilność, 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);
W wyniku tego powstanie tablica przesunięć układu, które nie są poprzedzone zdarzeniami wejściowymi:
[
{
"name": "",
"entryType": "layout-shift",
"startTime": 210.78500000294298,
"duration": 0,
"value": 0.0001045969445437389,
"hadRecentInput": false,
"lastInputTime": 0
}
]
W tym przykładzie wystąpiła jedna bardzo mała zmiana o 0,01% przy 210 ms.
Znajomość czasu i skali zmiany pomoże Ci zawęzić zakres możliwych 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 WebPageTest, pomiar poszczególnych przesunięć układu wymaga użycia danych niestandardowych. Na szczęście teraz, gdy Chrome 77 jest już stabilną wersją, proces ten jest łatwiejszy. Interfejs Layout Instability API jest domyślnie włączony, więc możesz wykonać ten fragment kodu JavaScript 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ć o flagi wiersza poleceń ani o korzystanie z Chrome Canary.
Zmodyfikujmy ten skrypt, aby uzyskać 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 rozwiązywana jako reprezentacja JSON tablicy, a nie sama tablica. Dzieje się tak, ponieważ dane niestandardowe mogą generować tylko proste typy danych, takie jak ciągi znaków lub liczby.
Do testu użyję witryny ismyhostfastyet.com, którą utworzyłem, aby porównywać rzeczywistą szybkość wczytywania danych przez dostawców hostingu.
Określanie przyczyn niestabilności układu
W wynikach 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 3087 ms następuje jedno przesunięcie układu o 34,2%. Aby zidentyfikować przyczynę problemu, użyjemy widoku paska zdjęć w WebPageTest.

Przewinięcie do około 3 sekundy w pasku filmu pokazuje, co jest przyczyną przesunięcia układu o 34%: kolorowa tabela. Witryna asynchronicznie pobiera plik JSON, a następnie renderuje go w tabeli. Tabela jest początkowo pusta, więc oczekiwanie na jej wypełnienie po wczytaniu wyników powoduje przesunięcie.

Ale to nie wszystko. Gdy strona jest wizualnie kompletna (po około 4,3 sekundy), widzimy, że <h1>
strony „Is my host fast yet?” pojawia się znikąd. Dzieje się tak, ponieważ witryna używa czcionki internetowej i nie podjęła żadnych działań w celu optymalizacji renderowania. W takiej sytuacji układ nie przesuwa się, ale długie oczekiwanie na przeczytanie tytułu jest niekorzystne dla użytkownika.
Naprawianie niestabilności układu
Wiemy już, że wygenerowana asynchronicznie tabela powoduje przesunięcie 1/3 obszaru widocznego, więc czas to naprawić. Nie znamy zawartości tabeli, dopóki nie zostaną załadowane wyniki JSON, ale możemy wypełnić ją danymi zastępczymi, aby układ był względnie stabilny po wyrenderowaniu 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'));
Dane zastępcze są generowane losowo przed posortowaniem. Zawiera znak „█” powtórzony losową liczbę razy, aby utworzyć wizualne symbole zastępcze tekstu, oraz losowo wygenerowany rozkład 3 głównych wartości. Dodałem też style, aby usunąć wszystkie kolory z tabeli i pokazać, że dane nie zostały jeszcze w pełni wczytane.
Wygląd używanych przez Ciebie elementów zastępczych nie ma znaczenia dla stabilności układu. Celem tych elementów jest zapewnienie użytkowników, że treść się pojawi, a strona nie jest uszkodzona.
Oto jak wyglądają symbole zastępcze podczas wczytywania danych JSON:

Rozwiązanie problemu z czcionką internetową jest znacznie prostsze. Ponieważ witryna korzysta z Czcionek Google, wystarczy przekazać właściwość display=swap
w żądaniu CSS. To wszystko. Interfejs Fonts API doda styl font-display: swap
do deklaracji czcionki, dzięki czemu przeglądarka będzie mogła od razu renderować tekst w czcionce zastępczej. Oto odpowiedni kod ze zmianą:
<link href="https://fonts.googleapis.com/css?family=Chivo:900&display=swap" rel="stylesheet">
Weryfikowanie optymalizacji
Po ponownym uruchomieniu strony w WebPageTest możemy wygenerować porównanie przed i po zmianach, aby wizualnie przedstawić różnicę i zmierzyć nowy stopień niestabilności układu:

[
{
"name": "",
"entryType": "layout-shift",
"startTime": 3070.9349999997357,
"duration": 0,
"value": 0.000050272187989256116,
"hadRecentInput": false,
"lastInputTime": 0
}
]
Według niestandardowego wskaźnika przesunięcie układu nadal występuje po 3071 ms (mniej więcej w tym samym czasie co wcześniej), ale jego nasilenie jest znacznie mniejsze: 0,005%. Mogę z tym żyć.
Z paska filmowego widać też, że czcionka <h1>
od razu przełącza się na czcionkę systemową, dzięki czemu użytkownicy mogą szybciej ją odczytać.
Podsumowanie
Złożone witryny prawdopodobnie będą miały znacznie więcej zmian układu niż w tym przykładzie, ale proces naprawy jest taki sam: dodaj do WebPageTest dane o niestabilności układu, porównaj wyniki z wizualnym paskiem filmu wczytywania, aby zidentyfikować przyczyny problemu, i wprowadź poprawkę, używając elementów zastępczych do rezerwowania miejsca na ekranie.
(Jeszcze jedna rzecz) Pomiar niestabilności układu odczuwanej przez rzeczywistych użytkowników
Możliwość uruchomienia WebPageTest na stronie przed optymalizacją i po niej oraz sprawdzenia, czy nastąpiła poprawa w przypadku danego wskaźnika, jest przydatna, ale najważniejsze jest to, aby wrażenia użytkowników rzeczywiście się poprawiły. Czy nie dlatego staramy się ulepszyć witrynę?
Dlatego warto zacząć mierzyć niestabilność układu u prawdziwych użytkowników, a także tradycyjne wskaźniki wydajności witryny. To kluczowy element pętli informacji zwrotnych dotyczących optymalizacji, ponieważ dane z terenu pokazują, gdzie występują problemy i czy nasze poprawki przyniosły pozytywne efekty.
Oprócz zbierania własnych danych o niestabilności układu sprawdź Raport na temat użytkowania Chrome, który zawiera dane o skumulowanym przesunięciu układu na podstawie wrażeń prawdziwych użytkowników w milionach witryn. Dzięki niemu możesz sprawdzić, jak radzisz sobie Ty (lub Twoja konkurencja), albo zbadać stan niestabilności układu w internecie.