Unikanie niepotrzebnych farb

Wprowadzenie

Malowanie elementów witryny lub aplikacji może być bardzo kosztowne i może mieć negatywny wpływ na wydajność w czasie działania. Z tego artykułu dowiesz się, co może powodować malowanie w przeglądarce i jak unikać niepotrzebnego malowania.

Obraz: bardzo szybki przegląd

Jednym z głównych zadań przeglądarki jest konwertowanie modelu DOM i CSS na piksele na ekranie. Jest to dość skomplikowany proces. Najpierw odczytuje znaczniki i na ich podstawie utworzy drzewo DOM. Podobnie działa w przypadku CSS, na podstawie którego tworzy CSSOM. DOM i CSSOM zostają następnie połączone i w końcu uzyskujemy strukturę, z której możemy zacząć malować kilka pikseli.

Sam proces malowania jest interesujący. W Chrome to połączone drzewo DOM i CSS jest rastrowane przez oprogramowanie o nazwie Skia. Jeśli kiedykolwiek korzystałeś/korzystałaś z interfejsu API elementu canvas, interfejs API Skia będzie Ci bardzo znajomy. Zawiera on wiele funkcji w stylu moveTolineTo, a także wiele bardziej zaawansowanych. Zasadniczo wszystkie elementy, które wymagają narysowania, są sprowadzane do kolekcji wywołań Skia, które można wykonać, a wyjściem jest zbiór bitmap. Te bitmapy są przesyłane do GPU, który komponuje je, aby uzyskać ostateczny obraz na ekranie.

Dom do pikseli

Warto zwrócić uwagę, że na zbiór zadań Skia bezpośrednio wpływają style, które zastosujesz do elementów. Jeśli używasz stylów o dużej złożoności obliczeniowej, Skia będzie musiał wykonać więcej pracy. Colt McAnlis napisał artykuł o tym, jak CSS wpływa na wagę renderowania strony. Warto go przeczytać, aby uzyskać więcej informacji.

Jednak malowanie zajmuje trochę czasu, a jeśli nie skrócimy tego procesu, przekroczymy budżet na klatkę wynoszący około 16 ms. Użytkownicy zauważą brakujące klatki i odczują to jako twarde przejście, co w efekcie pogorszy wrażenia z korzystania z aplikacji. Nie chcemy do tego dopuścić, więc sprawdźmy, co powoduje konieczność wykonania pracy związanej z malowaniem i jak możemy temu zaradzić.

Przewijanie

Gdy przewijasz w górę lub w dół w przeglądarce, musi ona ponownie narysować zawartość, zanim pojawi się na ekranie. Wszystko w porządku, to tylko mały obszar, ale nawet jeśli tak jest, do elementów, które należy narysować, można zastosować złożone style. To, że masz do pomalowania niewielką powierzchnię, nie oznacza, że uda Ci się to szybko.

Aby zobaczyć, które obszary są ponownie malowane, możesz użyć funkcji „Pokaż prostokąty malowania” w Narzędziach dewelopera w Chrome (wystarczy kliknąć kółko w prawym dolnym rogu). Gdy otworzysz Narzędzia deweloperskie, po prostu wejdź w interakcję ze stroną, a migające prostokąty pokazują, gdzie i kiedy Chrome namalował fragment strony.

Pokazuj prostokąty malowania w Narzędziach deweloperskich w Chrome
Pokazuj prostokąty malowania w Narzędziach deweloperskich w Chrome

Wydajność przewijania ma kluczowe znaczenie dla sukcesu witryny. Użytkownicy bardzo dobrze zauważają, gdy witryna lub aplikacja nie przewija się płynnie, i nie lubią tego. Dlatego zależy nam na tym, aby podczas przewijania animacja była lekka, aby użytkownicy nie widzieli zacięć.

Jeśli chcesz dowiedzieć się więcej o szczegółach dotyczących szybkości przewijania, przeczytaj artykuł na ten temat.

Interakcje

Inną przyczyną jest interakcja: najechanie kursorem, kliknięcie, dotknięcie lub przeciągnięcie. Gdy użytkownik wykona jedną z tych interakcji, np. najedzie kursorem, Chrome musi ponownie wyrenderować element, którego dotyczy problem. Podobnie jak w przypadku przewijania, jeśli wymagane jest namalowanie dużej i złożonej grafiki, nastąpi spadek liczby klatek.

Każdy chce ładnych i gładkich animacji interakcji, więc znowu musimy sprawdzić, czy zmiany stylu animacji nie pochłaniają nam zbyt dużo czasu.

Niefortunna kombinacja

Prezentacja z drogimi farbami
Demo z drogimi farbami

Co się dzieje, gdy jednocześnie przewijam widok i poruszę myszą? Jest bardzo możliwe, że przypadkowo „wejdę w interakcję” z elementem, gdy go przewinę, powodując kosztowne wyrenderowanie. To z kolei może zwiększyć mój budżet klatek na sekundę wynoszący ok.16,7 ms (czyli czas, który musi być poniżej tej wartości, aby osiągnąć 60 klatek na sekundę). Aby dokładnie pokazać, o co chodzi, utworzyliśmy wersję demonstracyjną. Mam nadzieję, że podczas przewijania i poruszania kursorem zobaczysz efekty najechania kursorem, ale zobaczmy, co w tej kwestii pokazują Narzędzia deweloperskie w Chrome:

Narzędzia deweloperskie w Chrome wyświetlają kosztowne ramki
Narzędzia deweloperskie w Chrome wyświetlają kosztowne klatki

Na powyższym obrazie widać, że DevTools rejestruje pracę z paintem, gdy najeżdżam kursorem na jeden z bloków. W tym celu w moim pokazie demo używam bardzo ciężkich stylów, co powoduje, że mój budżet ramek jest czasem przekraczany. Nie chcę niepotrzebnie wykonywać tej pracy, zwłaszcza podczas przewijania, gdy trzeba robić inne rzeczy.

Jak możemy temu zapobiec? Jak już wspomniano, rozwiązanie problemu jest dość proste. Wystarczy dołączyć scroll, który wyłączy efekty najechania kursorem i ustawi zegar, który je ponownie włączy. Oznacza to, że gwarantujemy, że podczas przewijania nie będziemy musieli wykonywać drogich operacji interakcji. Gdy odczekasz wystarczająco długo, uznamy, że można je ponownie włączyć.

Oto kod:

// Used to track the enabling of hover effects
var enableTimer = 0;

/*
 * Listen for a scroll and use that to remove
 * the possibility of hover effects
 */
window.addEventListener('scroll', function() {
  clearTimeout(enableTimer);
  removeHoverClass();

  // enable after 1 second, choose your own value here!
  enableTimer = setTimeout(addHoverClass, 1000);
}, false);

/**
 * Removes the hover class from the body. Hover styles
 * are reliant on this class being present
 */
function removeHoverClass() {
  document.body.classList.remove('hover');
}

/**
 * Adds the hover class to the body. Hover styles
 * are reliant on this class being present
 */
function addHoverClass() {
  document.body.classList.add('hover');
}

Jak widać, korzystamy z klasy w treści, aby śledzić, czy efekty najechania kursorem są „dozwolone”, a dostępne style zależą od obecności tej klasy:

/* Expect the hover class to be on the body
 before doing any hover effects */
.hover .block:hover {
 
}

To wszystko.

Podsumowanie

Wydajność renderowania ma kluczowe znaczenie dla użytkowników korzystających z Twojej aplikacji. Zawsze staraj się, aby czas renderowania nie przekraczał 16 ms. Aby Ci w tym pomóc, wdrażaj rozwiązania przy użyciu Narzędzi deweloperskich na etapie programowania, aby wykrywać i rozwiązywać wąskie gardła.

Nieumyślne interakcje, zwłaszcza w przypadku malowanych elementów, mogą być bardzo kosztowne i obniżać wydajność renderowania. Jak wiesz, możemy to naprawić za pomocą małego fragmentu kodu.

Sprawdź swoje witryny i aplikacje. Czy potrzebują ochrony przed blaknięciem?