Układ to na nim przeglądarka określa informacje geometryczne o elementach – ich rozmiarze i położeniu na stronie. Każdy element będzie zawierać wyraźne lub niejawne informacje o rozmiarze ustalone na podstawie użytego kodu CSS, zawartości elementu lub elementu nadrzędnego. Ten proces nazywa się układem w Chrome.
Układ to na nim przeglądarka określa informacje geometryczne o elementach: ich rozmiar i lokalizację na stronie. Każdy element będzie zawierać wyraźne lub niejawne informacje o rozmiarze ustalone na podstawie użytego kodu CSS, zawartości elementu lub elementu nadrzędnego. Ten proces nazywa się Układ w Chrome (i w przeglądarkach pochodnych, takich jak Edge) i Safari. W Firefoksie nazywa się to „przepływem”, ale proces jest w podstawie taki sam.
Podobnie jak w przypadku obliczeń dotyczących stylu, najważniejsze kwestie dotyczące kosztów układu to:
- Liczba elementów wymagających układu, która jest pochodną rozmiaru DOM strony.
- złożoność tych układów;
Podsumowanie
- Układ ma bezpośredni wpływ na opóźnienie interakcji
- Układ jest zwykle ograniczony do całego dokumentu.
- Liczba elementów DOM wpływa na skuteczność. Gdy tylko jest to możliwe, unikaj aktywowania układu.
- Unikaj wymuszania układów synchronicznych i zbędnego stosowania układów; odczytaj wartości stylów, a następnie wprowadź zmiany w stylach.
Wpływ układu na opóźnienie interakcji
Gdy użytkownik wchodzi w interakcję ze stroną, powinny one trwać jak najszybciej. Czas, jaki zajmuje interakcja (kończy się, gdy przeglądarka wyświetli kolejny kadr, aby pokazać wyniki interakcji), to opóźnienie interakcji. Jest to jeden z aspektów wydajności strony, który mierzy wskaźnik interakcja do kolejnego wyrenderowania.
Czas, jaki przeglądarka potrzebuje na wyświetlenie kolejnego klatki w odpowiedzi na interakcję użytkownika, nazywany jest opóźnieniem wyświetlania. Celem interakcji jest wyświetlenie wizualnej informacji zwrotnej, która sygnalizuje użytkownikowi, że coś się stało. Aby to osiągnąć, konieczne może być wprowadzenie pewnych zmian w układzie.
Aby jak najbardziej obniżyć INP witryny, należy unikać układu, jeśli to możliwe. Jeśli nie można całkowicie uniknąć układu, należy ograniczyć jego działanie, aby przeglądarka mogła szybko wyświetlić następny kadr.
Unikaj układu, o ile to możliwe
Gdy zmienisz style, przeglądarka sprawdza, czy któraś z tych zmian wymaga obliczenia układu i zaktualizowania drzewa renderowania. Zmiany we „właściwościach geometrycznych”, takich jak szerokość, wysokość, lewo i 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, ustalenie ich lokalizacji i wymiarów może zająć dużo czasu.
Jeśli nie można uniknąć układu, należy ponownie użyć narzędzi programistycznych Chrome, aby sprawdzić, ile czasu zajmuje działanie, i określić, czy układ jest przyczyną wąskiego gardła. Najpierw otwórz Narzędzia deweloperskie, przejdź na kartę Oś czasu, kliknij „Rejestruj” i wejdź w interakcję ze swoją witryną. Po zatrzymaniu nagrywania zobaczysz zestawienie skuteczności witryny:
Po zapoznaniu się z wykresem w powyższym przykładzie widzimy, że na układ w przypadku każdej klatki zużywa się ponad 28 ms, co jest zbyt dużo, biorąc pod uwagę, że na wyświetlenie klatki w ramach animacji mamy 16 ms. Widzisz też, że DevTools podaje rozmiar drzewa (w tym przypadku 1618 elementów) oraz ile węzłów wymaga układu (w tym przypadku 5).
Pamiętaj, aby unikać układu, gdy tylko jest to możliwe, ale nie zawsze można go uniknąć. W przypadkach, gdy nie możesz uniknąć układu, pamiętaj, że jego koszt jest powiązany z rozmiarem DOM. Chociaż związek między tymi dwoma parametrami nie jest ścisły, większe DOM-y będą zazwyczaj generować wyższe koszty układu.
Unikaj wymuszonych układów synchronicznych
Przesyłanie ramki do ekranu odbywa się w tej kolejności:
Najpierw wykonywany jest kod JavaScript, potem obliczenia stylu, potem układ. Można jednak zmusić przeglądarkę do wykonania układu wcześniej za pomocą JavaScriptu. Jest to tzw. wymuszony układ synchroniczny.
Przede wszystkim pamiętaj, że gdy JavaScript uruchamia wszystkie wartości układu z poprzedniej ramki, są one znane i możesz je wyszukiwać. Jeśli na przykład chcesz zapisać wysokość elementu (nazwijmy go „pudełko”) na początku klatki, 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);
}
Problemy mogą pojawić się, jeśli zmienisz styl pudełka przed określeniem jego wysokości:
function logBoxHeight () {
box.classList.add('super-big');
// Gets the height of the box in pixels and logs it out:
console.log(box.offsetHeight);
}
Aby odpowiedzieć na pytanie o wysokość, przeglądarka musi najpierw zastosować zmianę stylu (z powodu dodania klasy super-big
), a potem uruchomić układ. Dopiero wtedy będzie można zwrócić prawidłową wysokość. Jest to zbędna i potencjalnie kosztowna praca.
Z tego powodu zawsze wykonuj zbiorcze odczyty stylów i najpierw je wykonuj (gdzie przeglądarka może używać wartości układu z poprzedniego kadru), a potem wykonaj wszystkie zapisy:
Poprawnie wykonana funkcja 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 trzeba stosować stylów, a potem wartości zapytań. Wystarczy użycie wartości z ostatniego kadru. Wykonywanie obliczeń stylów i układów w sposób synchroniczny oraz wcześniej niż chce tego przeglądarka może być potencjalnym punktem wąskim i nie jest to coś, czego zwykle się chce.
Unikaj niepotrzebnego przeładowania układu
Istnieje sposób na jeszcze gorsze wymuszanie układów synchronicznych: wykonywanie ich w dużej liczbie 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`;
}
}
Kod zapętla grupę akapitów i ustawia szerokość każdego akapitu na szerokość elementu o nazwie „box”. Wygląda to niewinnie, ale problem polega na tym, że każda iteracja pętli odczytuje wartość stylu (box.offsetWidth
), a następnie od razu użyje jej do zaktualizowania szerokości akapitu (paragraphs[i].style.width
). W następnej iteracji pętli przeglądarka musi wziąć pod uwagę fakt, że od ostatniego wywołania funkcji offsetWidth
(w poprzedniej iteracji) zmieniły się style, więc musi zastosować zmiany stylu i uruchomić układ. Będzie to miało miejsce podczas każdej iteracji.
Aby rozwiązać ten problem, ponownie odczytaj, a potem zapisz wartości:
// 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 mieć pewność, że wszystko będzie działać prawidłowo, użyj FastDOM, który automatycznie grupował będzie Twoje operacje odczytu i zapisu. Dzięki temu nie będziesz przypadkowo uruchamiać wymuszonych synchronicznych układów ani niepotrzebnie nie uruchamiać funkcji layout thrashing.