W kierunku wskaźnika płynności animacji

Dowiedz się, jak mierzyć animacje, myśleć o klatkach animacji i ogólnej płynności strony.

Behdad Bakhshinategh
Behdad Bakhshinategh
Jonathan Ross
Jonathan Ross
Michal Mocny
Michal Mocny

Zdarza się pewnie, że strony „zacinają się” lub „zatrzymują się” podczas przewijania lub wyświetlania animacji. Lubimy twierdzić, że nie wszystko działa bezproblemowo. Aby rozwiązać tego typu problemy, zespół Chrome pracuje nad dodaniem większej pomocy do narzędzi laboratoryjnych dotyczących wykrywania animacji, a także nad ciągłym ulepszaniem diagnostyki potoku renderowania w Chromium.

Chcemy podzielić się najnowszymi postępami, zaoferować konkretne wskazówki dotyczące narzędzi i omówić pomysły na przyszłe wskaźniki płynności animacji. Chętnie poznamy Twoją opinię.

Ten post obejmuje 3 główne tematy:

  • Krótkie omówienie animacji i klatek animacji.
  • Nasze aktualne przemyślenia dotyczące pomiaru ogólnej płynności animacji.
  • Kilka praktycznych sugestii, które możesz dziś wykorzystać w narzędziach laboratoryjnych.

Czym są animacje?

Animacje ożywiają treści. Umożliwiają one poruszanie się treści, zwłaszcza w odpowiedzi na interakcje użytkownika, sprawiają, że korzystanie z aplikacji wydaje się bardziej naturalne, zrozumiałe i przyjemne.

Jednak słabo zaimplementowane animacje lub samo dodanie zbyt wielu animacji mogą pogorszyć wrażenia użytkowników i sprawić, że będą całkowicie nieprzyjemne. Do tej pory najczęściej korzystaliśmy już z interfejsu, który wprowadzał za dużo „pomocnych” efektów przejścia. Przy jego niskiej wydajności staje się to nieprzyjazne. Dlatego niektórzy użytkownicy mogą preferować ograniczenie ruchu. Należy je uwzględnić.

Jak działają animacje?

Potok renderowania składa się z kilku sekwencyjnych etapów:

  1. Styl: Obliczaj style zastosowane do elementów.
  2. Układ: wygeneruj geometrię i położenie każdego elementu.
  3. Farba: wypełnij piksele każdego elementu, tworząc warstwy.
  4. Kompozytowa: narysuj warstwy na ekranie.

Istnieje wiele sposobów definiowania animacji, ale wszystkie działają głównie dzięki jednej z tych metod:

  • Dostosowywanie właściwości układu.
  • Dostosowywanie właściwości renderowania.
  • Dostosowywanie właściwości kompozytowych.

Ponieważ te etapy są sekwencyjne, ważne jest definiowanie animacji pod kątem właściwości znajdujących się w dalszej części potoku. Im wcześniej odbywa się aktualizacja, tym większe są koszty i rzadziej wygląda to dobrze. (Więcej informacji znajdziesz w sekcji Wydajność renderowania).

Animacje właściwości układu są wygodne, ale wiąże się to z kosztami, nawet jeśli nie są one widoczne od razu. W miarę możliwości animacje powinny być definiowane za pomocą zmian właściwości złożonych.

Zdefiniowanie deklaratywnej animacji CSS lub użycie funkcji animacji internetowych i dodanie animacji właściwości złożonych to doskonały pierwszy krok do zapewnienia płynności i wydajności animacji. To jednak nie gwarantuje płynności, ponieważ nawet wydajne animacje internetowe mają ograniczenia wydajności. Dlatego zawsze należy dokonywać pomiarów.

Czym są klatki animacji?

Zmiany w wizualnej reprezentacji strony mogą pojawić się dopiero po pewnym czasie. Zmiana wizualnej spowoduje wyświetlenie nowej klatki animacji, która będzie renderowana na wyświetlaczu użytkownika.

Wyświetla aktualizacje co jakiś czas, dlatego aktualizacje wizualne są grupowane. Wiele wyświetla aktualizacje w stałym przedziale czasu, np. 60 razy na sekundę (60 Hz). Nowoczesne wyświetlacze mogą oferować wyższe częstotliwość odświeżania (coraz częściej 90–120 Hz). Często mogą one aktywnie dostosowywać częstotliwość odświeżania w zależności od potrzeb lub nawet w pełni zmieniać liczbę klatek.

Celem każdej aplikacji, takiej jak gra czy przeglądarka, jest przetworzenie wszystkich zbiorczych aktualizacji wizualnych i utworzenie wizualnej kompletnej klatki animacji w wyznaczonym terminie. Ten cel różni się całkowicie od innych ważnych zadań przeglądarki, takich jak szybkie ładowanie treści z sieci czy wydajne wykonywanie zadań JavaScript.

W pewnym momencie przeprowadzenie wszystkich aktualizacji wizualnych w wyznaczonym terminie może być zbyt trudne. W takim przypadku przeglądarka usuwa ramkę. Ekran nie zgaśnie, po prostu się powtarza. Widać tę samą aktualizację wizualną przez dłuższy czas – tę samą klatkę animacji, która była widoczna przy poprzedniej możliwości utworzenia klatki.

To zdarza się często. Niekoniecznie jest to w ogóle widoczne, zwłaszcza w przypadku treści statycznych lub przypominających dokumenty, które są bardzo powszechne na platformie internetowej. Pominięte klatki są widoczne tylko wtedy, gdy w filmie wprowadzono ważne zmiany wizualne, np. animacje, w przypadku których potrzebujemy ciągłych aktualizacji animacji, aby zapewnić płynny ruch.

Co wpływa na klatki animacji?

Programiści stron internetowych mogą mieć duży wpływ na szybkie i wydajne renderowanie oraz przedstawianie aktualizacji przez przeglądarkę.

Oto kilka przykładów:

  • Nie używaj treści, które są zbyt duże lub zużywają dużo zasobów, aby można było szybko je zdekodować na urządzeniu docelowym.
  • Zbyt wiele warstw wymaga zbyt dużej ilości pamięci GPU.
  • Definiowanie zbyt skomplikowanych stylów CSS lub animacji internetowych.
  • Zastosowanie antywzorców blokujących szybką optymalizację renderowania.
  • Zbyt dużo pracy JS w głównym wątku prowadzi do długich zadań blokujących aktualizacje wizualne.

Skąd jednak wiadomo, że klatka animacji przekroczyła termin i spowodowała spadek klatki?

Jedną z możliwych metod jest użycie ankiety requestAnimationFrame(), która ma jednak kilka wad. requestAnimationFrame() („rAF”) informuje przeglądarkę, że chcesz wykonać animację, i prosi o możliwość wykonania tej czynności przed następnym etapem renderowania potoku renderowania. Jeśli funkcja wywołania zwrotnego nie zostanie wywołana w oczekiwanym czasie, oznacza to, że renderowanie nie zostało wykonane, a co najmniej 1 klatka została pominięta. Odpytując i zliczając częstotliwość wywołań rAF, można obliczyć rodzaj wskaźnika „klatek na sekundę” (FPS).

let frameTimes = [];
function pollFramesPerSecond(now) {
  frameTimes = [...frameTimes.filter(t => t > now - 1000), now];
  requestAnimationFrame(pollFramesPerSecond);
  console.log('Frames per second:', frameTimes.length);
}
requestAnimationFrame(pollFramesPerSecond);

Użycie ankiet requestAnimationFrame() nie jest dobrym pomysłem z kilku powodów:

  • Każdy skrypt musi skonfigurować własną pętlę odpytywania.
  • Może zablokować ścieżkę krytyczną.
  • Nawet jeśli sondowanie rAF jest szybkie, może uniemożliwić usłudze requestIdleCallback() zaplanowanie długich bloków bezczynności, które są używane w trybie ciągłym (bloki przekraczające 1 klatkę).
  • Analogicznie brak długich blokad bezczynności uniemożliwia przeglądarce planowanie innych długotrwałych zadań (takich jak dłuższe odczyszczenie pamięci i inne działania w tle lub spekulacyjne).
  • Jeśli odpytywanie jest włączone i wyłączone, nie dostrzegasz przypadków, w których został przekroczony budżet ramki.
  • Ankiety badają wyniki fałszywie pozytywne w przypadku, gdy przeglądarka używa zmiennej częstotliwości aktualizacji (np. z powodu stanu zasilania lub widoczności).
  • Co najważniejsze, nie uwzględnia on wszystkich typów aktualizacji animacji.

Zbyt dużo pracy w wątku głównym może mieć wpływ na możliwość wyświetlania klatek animacji. Na stronie Jank Przykład możesz się dowiedzieć, jak animacja oparta na rAF, gdy w wątku głównym jest za dużo pracy (np. układ), dochodzi do pomijania klatek, mniejszej liczby wywołań zwrotnych RAF i niższych klatek na sekundę.

Gdy wątek główny się zatrzymuje, aktualizacje wizualne zaczynają się zacinać. Ale czad!

Wiele narzędzi pomiarowych stworzono z myślą o możliwości szybkiego wygenerowania klatek z wątku głównego oraz płynności animacji klatek animacji. To jednak nie wszystko. Na przykład:

Powyższy film przedstawia stronę, która okresowo wykonuje długie zadania w wątku głównym. Te długie zadania całkowicie utrudniają wprowadzanie określonych rodzajów aktualizacji wizualnych na stronie. W lewym górnym rogu widać odpowiadający jej spadek o requestAnimationFrame() liczby klatek na sekundę zgłoszony do 0.

Mimo to mimo długich zadań strona przewija się płynnie. W nowoczesnych przeglądarkach przewijanie jest często podzielone na wątki i w całości obsługiwane przez kompozytor.

W tym przykładzie zawiera jednocześnie wiele usuniętych klatek w wątku głównym, ale wciąż zawiera wiele pomyślnie przesłanych klatek przewijania w wątku kompozytora. Po ukończeniu długiego zadania aktualizacja malowania wątku nic nie zmienia wizualnego. W sondzie rAF zaproponowano spadek liczby klatek na 0, ale graficznie użytkownik nie byłby w stanie zauważyć różnicy.

W przypadku klatek animacji historia nie jest taka prosta.

Ramki animacji: istotne aktualizacje

Powyższy przykład pokazuje, że historia to nie tylko requestAnimationFrame().

Kiedy więc aktualizacje animacji i klatki animacji mają znaczenie? Oto kilka kryteriów, które rozważamy i chętnie poznamy Twoją opinię:

  • Aktualizacje wątku głównego i kompozytora
  • Brakujące aktualizacje dotyczące renderowania
  • Wykrywanie animacji
  • Jakość lub ilość

Aktualizacje wątku głównego i kompozytora

Aktualizacje ramki animacji nie są wartością logiczną. Nie chodzi tu o to, żeby klatki mogły zostać całkowicie usunięte lub przedstawione w całości. Istnieje wiele powodów, dla których ramka animacji może być częściowo prezentowana. Inaczej mówiąc, mogą zawierać pewne nieaktualne treści, a jednocześnie aktualizacje wizualne.

Najczęstszym przykładem jest sytuacja, w której przeglądarka nie może wygenerować nowej aktualizacji wątku głównego w terminie ramki, ale ma nową aktualizację wątku kompozytora (np. z wcześniejszego przykładu przewijania w wątkach).

Jednym z ważnych powodów, dla których zalecamy korzystanie z deklaratywnych animacji do animowania właściwości złożonych, jest to, że dzięki temu wątek kompozytora będzie w całości sterowany animacjam, nawet gdy wątek główny jest zajęty. Tego typu animacje nadal skutecznie i równolegle generują aktualizacje wizualne.

Z drugiej strony może się zdarzyć, że aktualizacja wątku głównego stanie się w końcu dostępna do prezentacji, ale dopiero po nieuwzględnieniu kilku terminów klatek. Tutaj przeglądarka otrzyma pewną aktualizację, ale może nie być najnowsza.

Ogólnie rzecz biorąc, nazywamy klatki z nowymi aktualizacjami wizualnymi, które nie zawierają tych zmian, jako częściową klatkę. Dosyć często zdarzają się częściowe klatki. W idealnej sytuacji częściowe aktualizacje zawierałyby przynajmniej najważniejsze aktualizacje wizualne, np. animacje, ale może to mieć miejsce tylko wtedy, gdy animacje są generowane przez wątek kompozytora.

Brakujące aktualizacje dotyczące renderowania

Kolejnym rodzajem częściowej aktualizacji jest sytuacja, w której multimedia takie jak obrazy nie zostały dekodowane i rasteryzują się na czas przed wyświetleniem klatki.

Nawet jeśli strona jest idealnie statyczna, przeglądarki mogą nie renderować aktualizacji wizualnych podczas szybkiego przewijania. Dzieje się tak, ponieważ odtworzenia treści w pikselach wykraczające poza widoczny widoczny obszar mogą zostać odrzucone, aby zaoszczędzić pamięć GPU. Renderowanie pikseli zajmuje trochę czasu, a wyrenderowanie całej klatki po dużym przewinięciu strony (np. przesunięciem palcem może zająć więcej czasu). Powszechnie nazywa się to szachownicą.

W przypadku każdej możliwości renderowania klatki można śledzić, jaka część najnowszych aktualizacji wizualnych faktycznie pojawiła się na ekranie. Pomiar tej możliwości na wielu klatkach (lub w czasie) jest powszechnie znany jako przepustowość ramki.

Jeśli GPU jest naprawdę przeciążone, przeglądarka (lub platforma) może nawet ograniczać szybkość, z jaką próbują zaktualizować elementy wizualne, i w ten sposób zmniejszać efektywną liczbę klatek. Chociaż może to zmniejszyć liczbę pomijanych aktualizacji klatek, wizualnie będzie się wyświetlać jako mniejsza przepustowość klatek.

Jednak nie wszystkie rodzaje małej przepustowości są złe. Jeśli strona jest w większości bezczynna i nie ma aktywnych animacji, niska liczba klatek jest równie atrakcyjna wizualnie jak wysoka liczba klatek (i może oszczędzać baterię).

Kiedy przepustowość klatek ma znaczenie?

Wykrywanie animacji

Duża przepustowość ma znaczenie, zwłaszcza w okresach z ważnymi animacjami. Różne typy animacji zależą od aktualizacji wizualnych z konkretnego wątku (głównego, kompozytora lub instancji roboczej), więc jego wizualna aktualizacja zależy od tego, jak ten wątek dostarczy aktualizację w wyznaczonym terminie. Mówimy, że dany wątek wpływa na płynność za każdym razem, gdy istnieje aktywna animacja zależna od aktualizacji wątku.

Niektóre typy animacji są łatwiejsze do definiowania i wykrywania niż inne. Animacje deklaratywne, czyli animacje oparte na danych wejściowych użytkownika, są łatwiejsze do zdefiniowania niż animacje oparte na języku JavaScript implementowane jako okresowe aktualizacje właściwości stylów animacji.

Nawet w przypadku requestAnimationFrame() nie zawsze możesz zakładać, że każde wywołanie rAF musi wygenerować wizualną aktualizację lub animację. Na przykład użycie sondowania rAF tylko do śledzenia liczby klatek (jak pokazano powyżej) nie powinno wpływać na pomiary płynności, ponieważ nie ma aktualizacji wizualnej.

Jakość lub ilość

Wykrywanie animacji i aktualizacji klatek animacji to nadal tylko część historii, ponieważ uwzględnia tylko liczbę aktualizacji animacji, a nie ich jakość.

Na przykład podczas oglądania filmu możesz widzieć stałą szybkość klatek 60 kl./s. Pod względem technicznym jest to idealnie płynne, ale sam film może mieć małą szybkość transmisji bitów lub mieć problemy z buforowaniem sieciowym. Nie uwzględnią tego bezpośrednio wskaźniki płynności animacji, ale nadal mogą być drażniące dla użytkownika.

Z kolei gra, która korzysta z <canvas> (nawet przy użyciu technik takich jak kanwy poza ekranem, aby zapewnić stałą liczbę klatek), może być technicznie idealnie płynna pod względem klatek animacji, bez ładowania wysokiej jakości zasobów gry w scenie lub wyświetlania artefaktów renderowania.

I oczywiście strona może zawierać naprawdę kiepskie animacje 🙂

GIF w budowie starej szkoły

Jak na swoje czasy były całkiem niezłe!

Stany pojedynczej klatki animacji

Jako że klatki mogą być prezentowane częściowo lub pomijane klatki mogą wystąpić w sposób, który nie wpływa na płynność, zaczęliśmy myśleć o każdej z nich jako o kompletności lub płynności.

Oto spektrum sposobów, w jakie interpretujemy stan pojedynczej klatki animacji, uporządkowaną od najlepszych do najgorszych:

Brak prośby o aktualizację Czas bezczynności, powtórzenie poprzedniej klatki.
Wszystkie materiały Aktualizacja wątku głównego została zatwierdzona w terminie lub nie była potrzebna żadna aktualizacja wątku głównego.
Częściowo prezentowane Tylko kompozytor; opóźniona aktualizacja wątku głównego nie spowodowała żadnych zmian wizualnych.
Częściowo prezentowane Tylko kompozytor; wątek główny otrzymał aktualizację wizualną, ale aktualizacja nie zawierała animacji, która wpływa na płynność.
Częściowo prezentowane Tylko kompozytor; w wątku głównym pojawiła się aktualizacja wizualna, która wpływa na płynność działania, ale pojawiła się wcześniej nieaktualna ramka i została użyta.
Częściowo prezentowane Tylko kompozytor; bez wymaganej głównej aktualizacji, a aktualizacja kompozytora zawiera animację, która wpływa na płynność.
Częściowo prezentowane Tylko kompozytor, ale aktualizacja kompozytora nie ma animacji, która wpływa na płynność.
Usunięta ramka Brak aktualizacji. Nie była potrzebna aktualizacja kompozytora, a główny był opóźniony.
Usunięta ramka Była wymagana aktualizacja kompozytora, ale była opóźniona.
Nieaktualna ramka Pożądana była aktualizacja. Została ona utworzona przez mechanizm renderowania, ale w GPU jeszcze jej nie było przed terminem vsync.

Te stany można przekształcić w pewną ocenę. Jednym ze sposobów interpretacji tego wyniku jest uznanie go za prawdopodobieństwo dostrzegalności przez użytkownika. Pojedyncza upuszczona klatka może nie być zbyt obserwacyjna, ale sekwencja wielu pominiętych klatek wpływa na płynność rzędu.

Podsumowanie: dane (procent utraconych klatek)

Dogłębne przeanalizowanie stanu każdej klatki animacji może być konieczne, ale warto też po prostu przypisać szybko ocenę w skrócie.

Ramki mogą być częściowo prezentowane, a nawet całkowicie pominięte aktualizacje klatek mogą nie mieć wpływu na ich płynność, dlatego chcemy skupić się bardziej na liczbie ramek, a nie na zakresie, w jakim przeglądarka nie jest w stanie dostarczyć pełnych wizualnych aktualizacji w odpowiednim momencie.

Model myślowy powinien przejść od:

  1. Kl. na sekundę, aby
  2. wykrywanie brakujących i ważnych aktualizacji animacji,
  3. Spadek wartości procentowej w danym okresie.

Liczy się tylko odsetek czasu oczekiwania na ważne aktualizacje. Naszym zdaniem jest to naturalny sposób, w jaki użytkownicy doświadczają płynności treści internetowych. Do tej pory jako wstępny zestaw danych używaliśmy tych wartości:

  • Średni procent utraconych: dla wszystkich nieaktywnych klatek animacji na całej osi czasu
  • Najgorszy przypadek odsetka utraconych klatek: mierzone w ciągu 1 sekundy z przesuwanym oknem czasu.
  • 95. percentyl odsetka utraconych klatek: mierzone w ciągu 1 sekundy.

Wyniki te można dziś znaleźć w niektórych narzędziach dla programistów Chrome. Te dane skupiają się tylko na ogólnej przepustowości klatek, ale bierzemy też pod uwagę inne czynniki, takie jak czas oczekiwania na klatkę.

Wypróbuj je w narzędziach dla programistów.

Wyświetlacz HUD wydajności

Chromium ma ukryty pod flagą (chrome://flags/#show-performance-metrics-hud) interfejs HUD, który zawiera wyniki na żywo, takie jak podstawowe wskaźniki internetowe, a także kilka eksperymentalnych definicji płynności animacji, określanych na podstawie danych o procentowej liczbie utraconych klatek w danym okresie.

Wyświetlacz HUD wydajności

Statystyki renderowania klatek

Włącz „Statystyki renderowania ramek” w Narzędziach deweloperskich w ustawieniach renderowania, aby zobaczyć podgląd na żywo nowych klatek animacji. Są one oznaczone kolorami, co pozwala odróżnić częściowe aktualizacje od pełnych aktualizacji klatek. Podawana liczba klatek na sekundę dotyczy tylko pełnych klatek.

Statystyki renderowania klatek

Wyświetlający klatki w nagraniach profilu wydajności w Narzędziach deweloperskich

W panelu wydajności Narzędzi deweloperskich od dawna znajduje się widz z klatkami. Jednak trochę się to zmieniło, wraz ze sposobem działania nowoczesnego potoku renderowania. Ostatnio wprowadziliśmy wiele ulepszeń, nawet w najnowszej wersji Chrome Canary, co powinno znacznie ułatwić debugowanie animacji.

Okazuje się, że ramki w przeglądarce ramek są lepiej wyrównane względem granic vsync i są oznaczane kolorami w zależności od stanu. Wciąż nie jesteśmy w stanie w pełni zwizualizować wszystkich wymienionych powyżej niuansów, ale planujemy dodać ich więcej w najbliższej przyszłości.

Przeglądarka ramek w Narzędziach deweloperskich w Chrome

Śledzenie w Chrome

Na koniec dzięki śledzeniu Chrome, czyli wybranym przez nas narzędziu do bardziej szczegółowej analizy, możesz zarejestrować log czasu „Renderowanie treści internetowych” za pomocą nowego interfejsu Perfetto (czyli about:tracing) i zapoznać się z grafiką Chrome. To może być trudne, ale w Chromium właśnie dodaliśmy kilka funkcji, by to ułatwić. Zapoznaj się z omówieniem zastosowań dokumentu Life of aFrame.

Za pomocą zdarzeń śledzenia można jednoznacznie określić:

  • są uruchomione animacje (korzystające ze zdarzeń o nazwie TrackerValidation).
  • Uzyskiwanie dokładnej osi czasu klatek animacji (przy użyciu zdarzeń o nazwie PipelineReporter).
  • W przypadku nieregularnych aktualizacji animacji dowiedz się, co uniemożliwia jej szybsze działanie (korzystając z podziałów zdarzeń w zdarzeniach PipelineReporter).
  • W przypadku animacji opartych na danych wejściowych sprawdź, ile czasu zajmuje aktualizacja wizualna (korzystając ze zdarzeń o nazwie EventLatency).

Raportujący potok potoku Chrome

Co dalej

Inicjatywa Wskaźniki internetowe ma na celu dostarczanie danych i wskazówek dotyczących zapewniania wysokiej jakości usług w internecie. Dane oparte na laboratorium, takie jak Total Block Time (TBT), są niezbędne do wychwytywania i diagnozowania potencjalnych problemów z interaktywnością. Zamierzamy opracować podobny, oparty na laboratoriach wskaźnik dla płynności animacji.

Będziemy Cię na bieżąco informować o pomysłach na zaprojektowanie wszechstronnych danych opartych na danych poszczególnych klatek animacji.

W przyszłości chcielibyśmy również opracować interfejsy API umożliwiające pomiar płynności animacji w przypadku rzeczywistych użytkowników w terenie oraz w laboratorium. Będziemy tam na bieżąco informować o zmianach.

Prześlij opinię

Z przyjemnością obserwujemy wszystkie najnowsze ulepszenia i narzędzia dla programistów w Chrome do pomiaru płynności animacji. Wypróbuj te narzędzia, porównaj swoje animacje i daj nam znać, co to oznacza.

Możesz wysyłać swoje komentarze do grupy dyskusyjnej Google web-vitals-feedback, wpisując temat „[Wskaźniki wygładzania]”. Chętnie poznamy Twoje zdanie.