Debuguj przesunięcia układu

Dowiedz się, jak rozpoznawać i rozwiązywać problemy z przesunięciami układu.

Katie Hempenius
Katie Hempenius

W pierwszej części tego artykułu omawiamy narzędzia do debugowania przesunięć układu, a w drugiej – proces myślowy przy identyfikowaniu przyczyny przesunięcia układu.

Narzędzia

Interfejs Layout Instability API

Układ interfejsu Instability API służy do pomiaru i raportowania przesunięć układu przeglądarki. Wszystkie narzędzia do debugowania przesunięć układu, w tym Narzędzia deweloperskie, opierają się ostatecznie na interfejsie Layout Instability API. Korzystanie z interfejsu Layout Instability API jest jednak wszechstronnym narzędziem do debugowania ze względu na jego elastyczność.

Wykorzystanie

Do debugowania przesunięć układu może służyć ten sam fragment kodu, który mierzy skumulowane przesunięcie układu (CLS). Poniższy fragment kodu zawiera informacje o przenoszeniu układu do konsoli. Przeanalizuj ten dziennik, aby dowiedzieć się, kiedy, gdzie i jak doszło do przesunięcia układu.

let cls = 0;
new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

Uruchamiając ten skrypt, pamiętaj, że:

  • Opcja buffered: true wskazuje, że PerformanceObserver powinien sprawdzać w buforze wpisów wydajności przeglądarki pod kątem wpisów dotyczących wydajności, które zostały utworzone przed inicjowaniem obserwatora. W efekcie PerformanceObserver będzie raportować przesunięcia układu, które nastąpiły zarówno przed jego zainicjowaniem, jak i po nim. Pamiętaj o tym podczas analizowania logów konsoli. Początkowe przesunięcia układu mogą odzwierciedlać zaległości w raportach, a nie nagłe wystąpienie wielu zmian układu.
  • Aby uniknąć negatywnego wpływu na wydajność, PerformanceObserver czeka, aż wątek główny będzie nieaktywny, i będzie przesyłać raporty o przesunięciach układu. W zależności od tego, jak zajęty jest wątek główny, między momentem przesunięcia układu a zarejestrowaniem go w konsoli może wystąpić niewielkie opóźnienie.
  • Ten skrypt ignoruje przesunięcia układu, które nastąpiły w ciągu 500 ms od użytkownika i dlatego nie są uwzględniane w CLS.

Informacje o przesunięciach układu są raportowane przy użyciu kombinacji 2 interfejsów API: LayoutShift i LayoutShiftAttribution. Każdy z tych interfejsów został szczegółowo wyjaśniony w kolejnych sekcjach.

LayoutShift

Każde przesunięcie układu jest raportowane za pomocą interfejsu LayoutShift. Zawartość tego wpisu wygląda tak:

duration: 0
entryType: "layout-shift"
hadRecentInput: false
lastInputTime: 0
name: ""
sources: (3) [LayoutShiftAttribution, LayoutShiftAttribution, LayoutShiftAttribution]
startTime: 11317.934999999125
value: 0.17508567530168798

Powyższy wpis wskazuje przesunięcie układu, podczas którego zmieniły się 3 elementy DOM. Wynik przesunięcia układu dla tego konkretnego przesunięcia układu wyniósł 0.175.

Oto właściwości instancji LayoutShift, które są najbardziej przydatne przy debugowaniu przesunięć układu:

Właściwość Opis
sources Właściwość sources zawiera listę elementów DOM, które zostały przeniesione podczas przesunięcia układu. Ta tablica może zawierać maksymalnie 5 źródeł. Jeśli przesunięcie układu wpływa na więcej niż 5 elementów, raportowanych jest 5 największych (mierzonych przez wpływ na stabilność układu) źródeł przesunięcia układu. Te informacje są raportowane za pomocą interfejsu atrybucji LayoutShift Attribution (szczegóły poniżej).
value Właściwość value podaje wynik przesunięcia układu dla określonego przesunięcia układu.
hadRecentInput Właściwość hadRecentInput wskazuje, czy zmiana układu nastąpiła w ciągu 500 milisekund od danych wejściowych użytkownika.
startTime Właściwość startTime wskazuje, kiedy miało miejsce przesunięcie układu. Wartość startTime jest podawana w milisekundach i mierzona względem czasu rozpoczęcia wczytywania strony.
duration Właściwość duration będzie zawsze ustawiona na 0. Ta właściwość jest dziedziczona z interfejsu PerformanceEntry (interfejs LayoutShift rozszerza interfejs PerformanceEntry). Pojęcie czasu trwania nie dotyczy jednak zdarzeń przesunięcia układu, więc ma wartość 0. Informacje o interfejsie PerformanceEntry znajdziesz w spec.

LayoutShiftAttribution

Interfejs LayoutShiftAttribution opisuje jedno przesunięcie pojedynczego elementu DOM. Jeśli podczas przesunięcia układu przesunie się wiele elementów, właściwość sources zawiera wiele wpisów.

Na przykład poniższy kod JSON odpowiada przesunięciem układu z jednego źródła: przesunięciem elementu DOM <div id='banner'> w dół z y: 76 do y:246.

// ...
  "sources": [
    {
      "node": "div#banner",
      "previousRect": {
        "x": 311,
        "y": 76,
        "width": 4,
        "height": 18,
        "top": 76,
        "right": 315,
        "bottom": 94,
        "left": 311
      },
      "currentRect": {
        "x": 311,
        "y": 246,
        "width": 4,
        "height": 18,
        "top": 246,
        "right": 315,
        "bottom": 264,
        "left": 311
      }
    }
  ]

Właściwość node identyfikuje przesunięty element HTML. Najechanie kursorem na tę właściwość w Narzędziach deweloperskich spowoduje podświetlenie odpowiedniego elementu strony.

Właściwości previousRect i currentRect podają rozmiar i pozycję węzła.

  • Współrzędne x i y podają współrzędne X i Y zależnie od lewego górnego rogu elementu
  • Właściwości width i height podają odpowiednio szerokość i wysokość elementu.
  • Właściwości top, right, bottom i left podają wartości współrzędnych x lub y odpowiadające danej krawędzi elementu. Innymi słowy, wartość top jest równa y, a wartość bottom równa się y+height.

Jeśli wszystkie właściwości elementu previousRect mają wartość 0, oznacza to, że element stał się widoczny. Jeśli wszystkie właściwości elementu currentRect mają wartość 0, oznacza to, że element przesunął się poza widok.

Jedną z najważniejszych kwestii, o której należy pamiętać przy interpretowaniu tych danych, jest to, że elementy wymienione jako źródła to elementy, które przesunęły się podczas zmiany układu. Możliwe jednak, że te elementy są tylko pośrednio związane z „główną przyczyną” niestabilności układu. Oto kilka przykładów:

Przykład 1

To przesunięcie układu zostanie odnotowane z jednym źródłem: elementem B. Główną przyczyną tego przesunięcia układu jest jednak zmiana rozmiaru elementu A.

Przykład przesunięcia układu spowodowanego zmianą wymiarów elementu

Przykład 2

Przesunięcie układu w tym przykładzie zostanie odnotowane z 2 źródeł: elementu A i elementu B. Główną przyczyną tego przesunięcia układu jest zmiana położenia elementu A.

Przykład przesunięcia układu spowodowanego zmianą pozycji elementu

Przykład 3

Przesunięcie układu w tym przykładzie zostanie odnotowane z jednym źródłem: elementem B. Zmiana pozycji elementu B spowodowała przesunięcie układu.

Przykład przesunięcia układu spowodowanego zmianą pozycji elementu

Przykład 4

Choć element B zmienia rozmiar, w tym przykładzie nie ma przesunięcia układu.

Przykład elementu, który zmienia rozmiar, ale nie powoduje przesunięcia układu

Zapoznaj się z prezentacją zmian DOM raportowanych przez interfejs Layout Instability API.

DevTools

Panel wydajności

W panelu Możliwości w panelu Wydajność Narzędzi deweloperskich widać wszystkie zmiany układu, które zachodzą w danym śladzie wydajności nawet wtedy, gdy mają miejsce w ciągu 500 ms od interakcji użytkownika i dlatego nie są uwzględniane w CLS. Najechanie kursorem na określone przesunięcie układu w panelu Możliwości wyróżnia dany element DOM.

Zrzut ekranu przedstawiający przesunięcie układu wyświetlane w panelu Network (Sieć) w Narzędziach deweloperskich

Aby wyświetlić więcej informacji o przesunięciu układu, kliknij to przesunięcie układu, a następnie otwórz szufladę Podsumowanie. Zmiany wymiarów elementu są podawane w formacie [width, height]. Zmiany pozycji elementu są podawane w formacie [x,y]. Właściwość Zawiera ostatnie dane wejściowe wskazuje, czy zmiana układu nastąpiła w ciągu 500 ms od interakcji użytkownika.

Zrzut ekranu przedstawiający kartę „Podsumowanie” w Narzędziach deweloperskich z przesunięciem układu

Aby uzyskać informacje o czasie trwania przesunięcia układu, otwórz kartę Dziennik zdarzeń. Czas trwania przesunięcia układu można też oszacować, sprawdzając w panelu Możliwości długość czerwonego prostokąta przesunięcia układu.

Zrzut ekranu przedstawiający kartę Dziennik zdarzeń w Narzędziach deweloperskich z przesunięciem układu

Więcej informacji o korzystaniu z panelu Wydajność znajdziesz w dokumentacji analizy wydajności.

Podświetl regiony przesunięcia układu

Zaznaczanie obszarów przesunięcia układu może być przydatną techniką pozwalającą szybko i szybko poznać lokalizację i czas wprowadzania przesunięć układu na stronie.

Aby włączyć regiony przesunięcia układu w Narzędziach deweloperskich, otwórz Ustawienia > Więcej narzędzi > Renderowanie > Regiony przesunięcia układu, a potem odśwież stronę, którą chcesz debugować. Obszary przesunięcia układu będą przez chwilę podświetlone na fioletowo.

Proces myślenia o przyczynie przesunięć układu

Skorzystaj z poniższych instrukcji, aby zidentyfikować przyczynę przesunięcia układu niezależnie od tego, kiedy i jak ma ono miejsce. Te czynności można uzupełnić o uruchomienie narzędzia Lighthouse, ale pamiętaj, że Lighthouse może wykrywać tylko przesunięcia układu, które nastąpiły podczas wstępnego wczytywania strony. Dodatkowo Lighthouse może też sugerować tylko niektóre przyczyny przesunięcia układu, np. elementy obrazu, które nie mają wyraźnej szerokości ani wysokości.

Określanie przyczyny przesunięcia układu

Przesunięcia układu mogą być spowodowane tymi zdarzeniami:

  • zmiana położenia elementu DOM.
  • zmiany wymiarów elementu DOM.
  • Wstawienie lub usunięcie elementu DOM
  • Animacje, które aktywują układ

W szczególności element DOM bezpośrednio poprzedzający przesunięty element jest elementem, który z największym prawdopodobieństwem zostanie uwzględniony w „powodowaniu” przesunięcia układu. Aby więc ustalić, dlaczego doszło do zmiany układu, weź pod uwagę te kwestie:

  • Czy zmieniła się pozycja lub wymiary poprzedniego elementu?
  • Czy element DOM został wstawiony przed przesuniętym elementem lub usunięty?
  • Czy położenie przesuniętego elementu zostało wyraźnie zmienione?

Jeśli poprzedni element nie spowodował przesunięcia układu, kontynuuj wyszukiwanie, uwzględniając inne poprzedzające i pobliskie elementy.

Kierunek i odległość przesunięcia układu mogą też dostarczać wskazówek o głównej przyczynie. Na przykład duże przesunięcie w dół często oznacza wstawienie elementu DOM, natomiast przesunięcie układu o 1 lub 2 piksele często oznacza zastosowanie sprzecznych stylów CSS lub wczytania i zastosowania czcionki internetowej.

Diagram przedstawiający przesunięcie układu spowodowane przez zamianę czcionki
W tym przykładzie zamiana czcionek spowodowała przesunięcie elementów strony w górę o 5 pikseli.

Oto niektóre zachowania, które najczęściej powodują zdarzenia przesunięcia układu:

zmiany położenia elementu (nie wynikają z ruchu innego elementu).

Taka zmiana jest często efektem:

  • Arkusze stylów, które są ładowane z opóźnieniem, lub zastępują wcześniej zadeklarowane style.
  • Efekty animacji i przejścia.

Zmiany wymiarów elementu

Taka zmiana jest często efektem:

  • Arkusze stylów, które są ładowane z opóźnieniem, lub zastępują wcześniej zadeklarowane style.
  • Obrazy i elementy iframe bez atrybutów width i height, które są wczytywane po wyrenderowaniu boksu.
  • Bloki tekstu bez atrybutów width lub height, które po wyrenderowaniu tekstu zamieniają czcionki.

Wstawianie lub usuwanie elementów DOM

Często jest to spowodowane tymi sytuacjami:

  • Wstawianie reklam i umieszczanie reklam innych firm.
  • Wstawianie banerów, alertów i okna modalnego.
  • nieskończone przewijanie i inne wzorce UX, które wczytują dodatkowe treści ponad istniejącą treścią.

Animacje, które aktywują układ

Niektóre efekty animacji mogą wywoływać układ. Typowym przykładem jest sytuacja, w której elementy DOM są „animowane” przez zwiększanie właściwości takich jak top lub left zamiast użycia właściwości transform CSS. Więcej informacji znajdziesz w artykule Jak tworzyć animacje CSS o dużej skuteczności.

Odtwarzanie przesunięć układu

Nie możesz naprawić przesunięć układu, których nie można odtworzyć. Jedną z najprostszych i najefektywniejszych rzeczy, które można zrobić, aby lepiej poznać stabilność układu witryny, jest poświęcenie 5–10 minut na interakcję z witryną w celu wywołania zmian układu. W tym czasie pozostaw konsolę otwartą i używaj interfejsu Layout Instability API, aby raportować przesunięcia układu.

Jeśli trudno jest znaleźć takie zmiany, możesz powtórzyć to ćwiczenie na różnych urządzeniach i przy różnych szybkościach połączenia. W szczególności wolne połączenie może ułatwić wykrycie zmian układu. Aby ułatwić sobie przechodzenie między zmianami układu, możesz też użyć instrukcji debugger.

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    if (!entry.hadRecentInput) {
      cls += entry.value;
      debugger;
      console.log('Current CLS value:', cls, entry);
    }
  }
}).observe({type: 'layout-shift', buffered: true});

W przypadku problemów z układem, których nie da się odtworzyć w programie, rozważ użycie interfejsu Layout Instability API w połączeniu z wybranym narzędziem do logowania w interfejsie, aby zebrać więcej informacji na ich temat. Zapoznaj się z przykładowym kodem śledzenia największego przesuniętego elementu na stronie.