Unikaj dużych i złożonych układów oraz rzucania niepotrzebnych elementów

Układ określa geometryczne informacje o elementach – ich rozmiar i umiejscowienie na stronie. Każdy element będzie miał jawną lub niejawną informację o rozmiarze zależną od użytego kodu CSS, zawartości elementu lub elementu nadrzędnego. Proces ten nosi nazwę Układ w Chrome.

Układ to pole, w którym przeglądarka pobiera informacje geometryczne o elementach: ich rozmiar i położenie na stronie. Każdy element będzie miał jawną lub niejawną informację o rozmiarze zależną od użytego kodu CSS, zawartości elementu lub elementu nadrzędnego. W Chrome (i w przeglądarkach derywowanych, np. Edge) lub Safari, nosi on nazwę Układ. W przeglądarce Firefox jest to nazwa Reflow, ale w rzeczywistości proces jest taki sam.

Podobnie jak w przypadku obliczania kosztów układu, bezpośrednie obawy o koszt układu są następujące:

  1. Liczba elementów wymagających układu, który jest iloczynem rozmiaru DOM strony.
  2. złożoność tych układów;

Podsumowanie

  • Układ ma bezpośredni wpływ na czas oczekiwania na interakcję
  • Układ jest zwykle ograniczony do całego dokumentu.
  • Liczba elementów DOM wpływa na wydajność. W miarę możliwości unikaj uruchamiania układu.
  • Unikaj wymuszonych układów synchronicznych i umiarów. Odczytuj wartości stylu, a następnie wprowadź zmiany.

Wpływ układu na czas oczekiwania na interakcję

Gdy użytkownik wchodzi w interakcję ze stroną, powinny one następować jak najszybciej. Czas potrzebny na zakończenie interakcji, czyli do chwili, gdy przeglądarka wyświetli następną klatkę, aby zobaczyć wyniki interakcji, jest nazywany opóźnieniem interakcji. Jest to aspekt szybkości strony mierzony przez dane Interakcja przy kolejnym wyrenderowaniu.

Czas potrzebny przeglądarce na wyświetlenie następnej klatki w odpowiedzi na interakcję użytkownika jest nazywany opóźnieniem prezentacji. Celem interakcji jest sygnalizowanie użytkownikowi, że coś się wydarzyło w formie wizualnej. Aby osiągnąć ten cel, zmiany wizualne mogą wymagać dodatkowego nakładu pracy.

Aby wartość INP witryny była jak najmniejsza, należy w miarę możliwości unikać układu strony. Jeśli nie da się całkowicie uniknąć układu, należy ograniczyć jego pracę, aby przeglądarka mogła szybko wyświetlić następną klatkę.

Unikaj układu, gdy to możliwe

Gdy zmieniasz style, przeglądarka sprawdza, czy któreś ze zmian wymagają obliczenia układu i zaktualizowania tego drzewa renderowania. Zmiany we „właściwościach geometrycznych”, takich jak szerokość, wysokość, lewo lub góra, wymagają układu.

.box {
  width: 20px;
  height: 20px;
}

/**
  * Changing width and height
  * triggers layout.
  */

.box--expanded {
  width: 200px;
  height: 350px;
}

Układ jest prawie zawsze ograniczony do całego dokumentu. Jeśli masz dużo elementów, określenie ich lokalizacji i wymiarów może zająć dużo czasu.

Jeśli nie da się uniknąć układu, najważniejsze jest, aby ponownie użyć Narzędzi deweloperskich w Chrome, aby sprawdzić, ile czasu to zajmuje, i określić, czy przyczyną wąskiego gardła jest układ strony. Najpierw otwórz Narzędzia deweloperskie, przejdź na kartę Oś czasu, kliknij przycisk nagrywania i wejdź w interakcję ze swoją witryną. Po zatrzymaniu rejestrowania zobaczysz zestawienie skuteczności witryny:

Narzędzia deweloperskie od dawna używane w Układach.

Analizując ślad w powyższym przykładzie, zauważymy, że czas trwania każdej klatki wynosi ponad 28 milisekund. Jeśli na wyświetlenie klatki na ekranie mamy 16 milisekund, jest to znacznie za dużo. Widać też,że Narzędzia deweloperskie podają rozmiar drzewa (w tym przypadku 1618 elementów) i liczbę węzłów, które wymagały układu (w tym przypadku 5).

Pamiętaj, że zgodnie z tą ogólną radą unikaj układu, gdy tylko to możliwe, ale nie zawsze da się go uniknąć. Jeśli nie można uniknąć układu, pamiętaj, że koszt układu jest powiązany z rozmiarem DOM. Chociaż relacje między nimi nie są ściśle sprzężone, większe DOMy zazwyczaj wiążą się z wyższymi kosztami.

Unikaj wymuszonych układów synchronicznych

Kolejność wyświetlania ramki na ekranie jest następująca:

Wykorzystanie Flexbox jako układu.

Najpierw uruchamia się JavaScript, potem wykonuje obliczenia stylu, a później układ. Można jednak wymusić na przeglądarce wcześniejsze wykonanie układu za pomocą JavaScriptu. Jest to tzw. wymuszony układ synchroniczny.

Przede wszystkim pamiętaj, że gdy JavaScript działa, wszystkie wartości starego układu z poprzedniej ramki są znane i możesz wysyłać do nich zapytania. Jeśli np. chcesz wpisać wysokość elementu (nazwijmy to „boxem”) na początku ramki, możesz napisać taki kod:

// Schedule our function to run at the start of the frame:
requestAnimationFrame(logBoxHeight);

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Jeśli zmienisz style pola, zanim poprosisz o jego wysokość:

function logBoxHeight () {
  box.classList.add('super-big');

  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);
}

Teraz, aby odpowiedzieć na pytanie dotyczące wysokości, przeglądarka musi najpierw zastosować zmianę stylu (przez dodanie klasy super-big), a potem uruchomić układ. Dopiero wtedy będzie można przywrócić prawidłową wysokość. Jest to zbędna i potencjalnie kosztowna praca.

Z tego względu należy zawsze grupować odczyty stylów i wykonywać je najpierw (tam, gdzie przeglądarka może korzystać z wartości układu poprzedniej ramki), a dopiero potem wykonywać zapisy:

Jeśli zostanie poprawnie wykonana, funkcja powyższa będzie wyglądać tak:

function logBoxHeight () {
  // Gets the height of the box in pixels and logs it out:
  console.log(box.offsetHeight);

  box.classList.add('super-big');
}

W większości przypadków nie musisz stosować stylów, a potem wysyłać zapytań o wartości – wystarczy skorzystać z wartości ostatniej ramki. Wykonywanie obliczeń dotyczących stylu oraz układu synchronicznie i wcześniej, niż by sobie życzyła przeglądarka, może powodować wąskie gardła i nie robić tego zazwyczaj.

Staraj się nie ścierać układu

Możesz jeszcze bardziej pogorszyć wymuszone układy synchroniczne: rób wiele tych układów w krótkich odstępach czasu. Spójrz na ten kod:

function resizeAllParagraphsToMatchBlockWidth () {
  // Puts the browser into a read-write-read-write cycle.
  for (let i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = `${box.offsetWidth}px`;
  }
}

Ten kod zapętla się na grupie akapitów i ustawia szerokość każdego z nich tak, by pasowała do szerokości elementu o nazwie „box”. Wygląda to niegroźnie, ale problem polega na tym, że każde wystąpienie pętli odczytuje wartość stylu (box.offsetWidth), a następnie natychmiast używa jej do zaktualizowania szerokości akapitu (paragraphs[i].style.width). Przy następnym powtórzeniu pętli przeglądarka musi uwzględniać fakt, że style zmieniły się od czasu ostatniego żądania offsetWidth (w poprzedniej iteracji), więc musi zastosować zmiany stylu i uruchomić układ. Będzie to miało miejsce przy każdej iteracji.

W tym przykładzie ponownie należy odczytać wartości read, a następnie write:

// Read.
const width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth () {
  for (let i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = `${width}px`;
  }
}

Jeśli chcesz zagwarantować bezpieczeństwo, rozważ użycie modelu FastDOM, który automatycznie grupuje odczyty i zapisy. Zapobiega wtedy przypadkowemu uruchomieniu wymuszonych układów synchronicznych i przypadkowym rzucaniu układu.

Baner powitalny ze zbioru Unsplash od Hal Gatewood.