Unikanie niepotrzebnych farb

Wstęp

Malowanie elementów witryny lub aplikacji może być naprawdę kosztowne i może mieć negatywny wpływ na wydajność naszego środowiska wykonawczego. W tym artykule przyglądamy się krótko, co może powodować wyświetlanie malowania w przeglądarce i jak możesz zapobiec pojawianiu się niepotrzebnych obrazów.

Malowanie: bardzo krótka prezentacja

Jednym z głównych zadań, które musi wykonać przeglądarka, jest przekształcenie DOM i CSS w piksele na ekranie. Jest to dość złożony proces. Zaczyna od odczytania znacznika, po czym tworzy drzewo DOM. Działa to podobnie z CSS, tworząc w ten sposób obiekt CSSOM. DOM i CSSOM są następnie łączone i w końcu dochodzimy do struktury, od której możemy zacząć malować piksele.

Sam proces malowania jest interesujący. W Chrome połączenie drzewa DOM i CSS jest zrastrowane przez oprogramowanie Skia. Wygląda na to, że interfejs API Skia elementu canvas wygląda znajomo. Masz do dyspozycji wiele funkcji w stylu moveTo i lineTo, a także kilka bardziej zaawansowanych. Zasadniczo wszystkie elementy, które trzeba pomalować, są wyodrębniane w zbiór wywołań Skia, które można wykonać, a wynikiem otrzymujemy mnóstwo map bitowych. Te bitmapy są przesyłane do GPU, a GPU pomaga, łącząc je ze sobą, aby uzyskać ostateczny obraz na ekranie.

Zamień na piksele

Należy pamiętać, że zadania Skiy bezpośrednio zależą od stylów zastosowanych do elementów. Jeśli używasz algorytmicznych stylów, Skia będzie mieć więcej do zrobienia. Colt McAnlis napisał artykuł o tym, jak CSS wpływa na wagę renderowania strony. Przeczytaj go, aby dowiedzieć się więcej.

Malarska ma jednak trochę czasu, a jeśli nie ograniczymy tego czasu, przekroczymy budżet na ok. 16 ms. Użytkownicy zauważą, że brakuje ramek, i będą postrzegać je jako zacinanie, co ostatecznie obniża komfort korzystania z aplikacji. Naprawdę tego nie chcemy, więc sprawdźmy, jakie czynniki powodują konieczność malowania i co możemy z tym zrobić.

Przewijanie

Za każdym razem, gdy przewijasz stronę w górę lub w dół, musisz ponownie wyrenderować treść, zanim pojawi się ona na ekranie. Zasadniczo jest to niewielki obszar, ale nawet jeśli tak jest, do elementów, które trzeba narysować, można zastosować złożone style. Fakt, że masz mały obszar do namalowania, nie oznacza, że wszystko to nastąpi szybko.

Aby zobaczyć, które obszary są malowane, możesz użyć funkcji „Pokaż malowane prostokąty” w Narzędziach deweloperskich w Chrome (po prostu kliknij ikonę koła zębatego w prawym dolnym rogu). Następnie po otwarciu Narzędzi deweloperskich możesz wejść w interakcję ze stroną, a zobaczysz, gdzie i kiedy Chrome namalował fragment strony.

Pokaż malowane prostokąty w Narzędziach deweloperskich w Chrome
Pokaż prostokąty z farbą w narzędziach deweloperskich w Chrome

Wydajność przewijania jest istotnym czynnikiem decydującym o sukcesie witryny. Użytkownicy naprawdę zauważają, że witryna lub aplikacja nie przewija się dobrze, i jest im to nietrafne. W związku z tym zależy nam na tym, aby malowanie świeciło się podczas przewijania strony, tak aby użytkownicy nie widzieli zacięć.

Napisałem już artykuł o wydajności przewijania, więc przeczytaj go, jeśli chcesz dowiedzieć się więcej o tym, jak działa przewijanie.

Interactions

Kolejną przyczyną malowania są interakcje: najechanie kursorem, kliknięcia, dotknięcia czy przeciągnięcie. Za każdym razem, gdy użytkownik wykona jedną z tych interakcji, np. najedziemy kursorem, Chrome będzie musiał ponownie wyrenderować dany element. Podobnie jak w przypadku przewijania, jeśli wymagane jest duże i złożone renderowanie, zauważysz spadek liczby klatek.

Wszyscy chcemy mieć ładne i płynne animacje interakcji, więc znowu musimy sprawdzić, czy style, które zmieniają się w animacji, nie pochłaniają zbyt dużo czasu.

Nieszczęśliwa kombinacja

Prezentacja drogich farb
Prezentacja z drogimi farbami

Co się stanie, jeśli przewinę widok i jednocześnie poruszam myszą? Możliwe, że nieumyślnie „wchodź w interakcję” z elementem, gdy go przewijam, co powoduje kosztowne renderowanie. To z kolei mogłoby spowodować przekroczenie budżetu wynoszącego ok.16, 7 ms (czas, który musimy zmieścić się poniżej 60 klatek na sekundę). Utworzyłem demonstrację, aby dokładnie pokazać, o co mi chodzi. Mamy nadzieję, że podczas przewijania i przesuwania myszą zauważysz efekty najechania kursorem. Zobaczmy jednak, jak działają Narzędzia deweloperskie w Chrome:

Narzędzia deweloperskie w Chrome z drogimi ramkami
Narzędzia deweloperskie w Chrome z drogimi ramkami

Na powyższej ilustracji widać, że Narzędzia deweloperskie rejestrują efekty renderowania, gdy najedziesz kursorem na jeden z bloków. Wybrałem w wersji demonstracyjnej kilka bardzo ciężkich stylów, więc od czasu do czasu przekraczam swój budżet. Ostatnią rzeczą, o której chcę, jest malowanie niepotrzebnie, zwłaszcza podczas przewijania, gdy jest coś do zrobienia.

Jak możemy temu zapobiec? Rozwiązanie problemu jest bardzo proste. Tu należy dołączyć moduł obsługi scroll, który będzie wyłączać efekty najechania kursorem i ustawiać licznik czasu, który umożliwi ich ponowne włączenie. Oznacza to, że gwarantujemy, że podczas przewijania nie będzie trzeba wykonywać kosztownych farb interaktywnych. Jeśli nie korzystasz z aplikacji na wystarczająco długo, możemy bezpiecznie włączyć ją z powrotem.

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ć, używamy klasy w treści do sprawdzania, czy efekty najechania kursorem są dozwolone, a obecne style bazują na tej klasie:

/* 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, którzy chętnie korzystają z Twojej aplikacji, dlatego zawsze staraj się utrzymywać nakład pracy poniżej 16 ms. W tym celu warto przeprowadzić integrację za pomocą Narzędzi deweloperskich w całym procesie programowania, co pozwoli zidentyfikować i eliminować pojawiające się wąskie gardła.

Nieumyślne interakcje, zwłaszcza w przypadku elementów zawierających dużo farby, mogą być bardzo kosztowne i zmniejszyć wydajność renderowania. Jak zapewne wiesz, możemy to naprawić za pomocą małego fragmentu kodu.

Przyjrzyj się swoim witrynom i aplikacjom – czy może wystarczy im odrobina ochrony przed farbą?