W kierunku wskaźnika płynności animacji

Dowiedz się więcej o mierzeniu animacji, kadrowaniu animacji i ogólnej płynności strony.

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

Prawdopodobnie zdarzyło Ci się, że strony „zacinały się” lub „zawieszały” podczas przewijania lub animacji. Te funkcje nie są płynne. Aby rozwiązać tego typu problemy, zespół Chrome pracował nad dodaniem obsługi narzędzi laboratoryjnych do wykrywania animacji, a także nad ulepszaniem diagnostyki ścieżki renderowania w Chromium.

Chcielibyśmy podzielić się z Tobą informacjami o ostatnich postępach, przedstawić konkretne wskazówki dotyczące narzędzi i przedstawić pomysły na przyszłe wskaźniki płynności animacji. Jak zawsze chętnie poznamy Twoją opinię.

W tym poście omawiamy 3 główne tematy:

  • Szybki przegląd animacji i klatek animacji
  • Nasze obecne przemyślenia na temat pomiaru ogólnej płynności animacji.
  • Kilka praktycznych sugestii dotyczących wykorzystania narzędzi laboratoryjnych.

Co to są animacje?

Animacje ożywiają treści. Dzięki animacjom treści mogą się poruszać, zwłaszcza w reakcji na interakcje użytkowników, co sprawia, że korzystanie z aplikacji jest bardziej naturalne, zrozumiałe i przyjemne.

Źle zaimplementowane animacje lub zbyt duża ich liczba mogą jednak pogorszyć wrażenia użytkownika i uczynić je nieprzyjemnymi. Wszyscy pewnie korzystaliśmy z interfejsu, do którego dodano zbyt wiele „użytecznych” efektów przejścia, które w rzeczywistości stają się nieprzyjemne, gdy działają nieprawidłowo. Niektórzy użytkownicy mogą preferować ograniczone ruchy, a to preferencje użytkownika, które należy uszanować.

Jak działają animacje?

Podsumujmy: przetwarzanie składa się z kilku kolejnych etapów:

  1. Style: obliczanie stylów zastosowanych do elementów.
  2. Układ: wygeneruj geometrię i położenie każdego elementu.
  3. Paint:wypełnij piksele każdego elementu warstwami.
  4. Kompozycja: rysowanie warstw na ekranie.

Chociaż animacje można definiować na wiele sposobów, wszystkie one działają w ten sam sposób:

  • Dostosowywanie właściwości układu.
  • Dostosowywanie właściwości paint.
  • Dostosowywanie właściwości kompozycji.

Ponieważ te etapy są uporządkowane chronologicznie, ważne jest, aby animacje definiować w oparciu o właściwości, które znajdują się dalej w łańcuchu przetwarzania. Im wcześniej nastąpiła aktualizacja, tym większe są koszty i tym mniejsze jest prawdopodobieństwo, że przebiegnie ona bezproblemowo. (więcej informacji znajdziesz w sekcji Wydajność renderowania).

Animacja właściwości układu może być wygodna, ale wiąże się z pewnymi kosztami, nawet jeśli nie są one od razu widoczne. W miarę możliwości animacje powinny być definiowane w sposób uwzględniający zmiany właściwości złożonych.

Aby zapewnić płynne i wydajne animacje, warto zacząć od deklaratywnych animacji CSS lub korzystania z animacji internetowych oraz animowania właściwości złożonych. Nie gwarantuje to jednak płynności, ponieważ nawet wydajne animacje internetowe mają ograniczenia wydajności. Dlatego zawsze warto mierzyć skuteczność.

Czym są klatki animacji?

Zmiany wizualne strony mogą się pojawić dopiero po pewnym czasie. Zmiana wizualna spowoduje utworzenie nowej klatki animacji, która ostatecznie zostanie wyrenderowana na ekranie użytkownika.

Wyświetla aktualizacje w określonych odstępach czasu, dzięki czemu aktualizacje wizualne są grupowane. Wiele wyświetlaczy aktualizuje się w określonym odstępie czasu, np. 60 razy na sekundę (czyli 60 Hz). Niektóre nowocześniejsze wyświetlacze mogą oferować wyższą częstotliwość odświeżania (90–120 Hz staje się coraz bardziej powszechne). Często takie wyświetlacze mogą aktywnie dostosowywać częstotliwość odświeżania do potrzeb lub nawet oferować zmienną częstotliwość odświeżania.

Celem każdej aplikacji, np. gry lub przeglądarki, jest przetworzenie wszystkich zbiorczych aktualizacji wizualnych i utworzenie kompletnego klatki animacji, która będzie wizualnie poprawna, zawsze w określonym czasie. Pamiętaj, że ten cel jest zupełnie inny od innych ważnych zadań przeglądarki, takich jak szybkie wczytywanie treści z sieci czy wydajne wykonywanie zadań JavaScript.

W pewnym momencie może okazać się zbyt trudne, aby w określonym terminie wprowadzić wszystkie zmiany wizualne. W takim przypadku przeglądarka wyrzuca ramkę. Ekran nie wraca do czarnego ekranu, tylko się powtarza. Widzisz tę samą aktualizację wizualną przez dłuższy czas – tę samą klatkę animacji, która została wyświetlona w poprzedniej klatce.

To się często zdarza. Nie musi być ona nawet zauważalna, zwłaszcza w przypadku treści statycznych lub podobnych do dokumentów, które są powszechne na platformach internetowych. Utrata klatek staje się widoczna tylko wtedy, gdy występują ważne zmiany wizualne, takie jak animacje, które wymagają ciągłego przesyłania aktualizacji animacji w celu zapewnienia płynnego ruchu.

Co wpływa na klatki animacji?

Deweloperzy internetowi mogą mieć duży wpływ na to, jak szybko i efektywnie przeglądarka będzie renderować oraz prezentować zmiany wizualne.

Oto kilka przykładów:

  • Używanie treści, które są zbyt duże lub wymagają zbyt wielu zasobów, aby można je było szybko zdekodować na urządzeniu docelowym.
  • Używanie zbyt wielu warstw, które wymagają zbyt dużej ilości pamięci GPU.
  • definiowanie zbyt złożonych stylów CSS lub animacji internetowych;
  • Używanie nieprawidłowych wzorów projektowania, które wyłączają optymalizacje szybkiego renderowania.
  • Zbyt dużo pracy związanej z JS w wątku głównym, co prowadzi do długich zadań, które blokują aktualizacje wizualne.

Ale jak możesz wiedzieć, kiedy klatka animacji nie zmieściła się w terminie i spowodowała pominięcie klatki?

Jedną z możliwych metod jest stosowanie requestAnimationFrame()ankiety, ale ma ona kilka wad. requestAnimationFrame(), czyli „rAF”, informuje przeglądarkę, że chcesz wykonać animację, i prosi o możliwość wykonania tego przed kolejnym etapem renderowania w pipeline. Jeśli funkcja wywołania zwrotnego nie zostanie wywołana w oczekiwanym czasie, oznacza to, że nie została wykonana funkcja paint, a co najmniej jeden lub więcej klatek zostało pominięte. Dzięki sprawdzaniu i liczeniu, jak często wywoływana jest funkcja RAF, możesz obliczyć „liczba 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);

Korzystanie z requestAnimationFrame() nie jest dobrym pomysłem z kilku powodów:

  • Każdy skrypt musi mieć własną pętlę sprawdzania.
  • Może to spowodować zablokowanie ścieżki krytycznej.
  • Nawet jeśli polling rAF jest szybki, może uniemożliwić requestIdleCallback() planowanie długich bloków bezczynności podczas ciągłego używania (bloków, które przekraczają 1 klatka).
  • Podobnie brak długich bloków bezczynności uniemożliwia przeglądarce zaplanowanie innych długotrwałych zadań (takich jak dłuższe zbieranie elementów do usunięcia i inne zadania w tle lub spekulatywne).
  • Jeśli polling jest włączony i wyłączony, nie zauważysz przypadków przekroczenia budżetu ramki.
  • W przypadku, gdy przeglądarka używa zmiennej częstotliwości aktualizacji (np. ze względu na stan zasilania lub widoczność), wywoływanie metody poll spowoduje fałszywie dodatnie wyniki.
  • Co najważniejsze, nie obejmuje ona wszystkich typów aktualizacji animacji.

Zbyt duża ilość pracy w wątku głównym może wpływać na możliwość wyświetlania klatek animacji. Sprawdź przykład Jank, aby zobaczyć, jak animacja obsługiwana przez rAF, gdy wątek główny ma zbyt dużo pracy (np. układ), powoduje utratę klatek, mniejszą liczbę wywołań zwrotnych rAF i niższą liczbę klatek na sekundę.

Gdy wątek główny zacznie się zacinać, aktualizacje wizualne zaczną się zacinać. To nie jest śmieszne.

Wiele narzędzi do pomiarów koncentrowało się głównie na tym, aby główny wątek mógł w swoim czasie zwracać wartości, a ramki animacji były wyświetlane płynnie. To jednak nie wszystko. Na przykład:

Film powyżej pokazuje stronę, która okresowo wstrzykuje długie zadania do głównego wątku. Te długie zadania całkowicie uniemożliwiają stronie wyświetlanie niektórych typów aktualizacji wizualnych. W lewym górnym rogu można zauważyć odpowiadający spadek requestAnimationFrame() zgłoszonych klatek na sekundę do 0.

Mimo tak długich zadań strona nadal płynnie się przewija. Dzieje się tak, ponieważ w nowoczesnych przeglądarkach przewijanie jest często wielowątkowe i w pełni zarządzane przez kompozytor.

Ten przykład zawiera jednocześnie wiele utraconych klatek na głównym wątku, ale nadal ma wiele prawidłowo przesłanych klatek przewijania na wątku kompozytora. Po zakończeniu długiego zadania aktualizacja głównego wątku nie wnosi żadnych zmian wizualnych. Ankieta z użyciem interfejsu raf sugeruje spadek liczby klatek do 0, ale wizualnie użytkownik nie zauważy różnicy.

W przypadku klatek animacji sprawa nie jest tak prosta.

Klatki animacji: ważne aktualizacje

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

Kiedy więc aktualizacje animacji i klatki animacji mają znaczenie? Oto niektóre kryteria, które bierzemy pod uwagę i na temat których chcielibyśmy uzyskać opinię:

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

Aktualizacje wątku głównego i wątku kompozytora

Aktualizacje klatek animacji nie są typu logicznego. Nie oznacza to, że klatki mogą być tylko całkowicie usunięte lub całkowicie wyświetlane. Istnieje wiele powodów, dla których kadr animacji może być częściowo wyświetlany. Innymi słowy, strona może zawierać niektóre nieaktualne treści, a jednocześnie nowe elementy wizualne.

Najczęstszym przykładem jest sytuacja, w której przeglądarka nie może przeprowadzić nowej aktualizacji głównego wątku w ramach limitu czasu kadru, ale ma nową aktualizację wątku kompozytora (np. w przykładzie przewijania w wątkach z poprzedniego akapitu).

Jednym z ważnych powodów, dla których zalecamy używanie deklaratywnych animacji do animowania właściwości złożonych, jest to, że umożliwia to sterowanie animacją wyłącznie przez wątek kompozytora, nawet gdy wątek główny jest zajęty. Te typy animacji mogą nadal zapewniać wydajne i równoległe aktualizacje wizualne.

Z drugiej strony, może się zdarzyć, że aktualizacja głównego wątku stanie się dostępna do wyświetlenia dopiero po przekroczeniu kilku terminów dotyczących klatek. W tym przypadku przeglądarka będzie w jakiejś nowszej wersji, ale nie będzie to najnowsza.

Ogólnie mówiąc, ramki, które zawierają niektóre nowe elementy wizualne, ale nie wszystkie, uznajemy za częściowe ramki. Częściowe klatki są dość powszechne. W idealnej sytuacji aktualizacje częściowe obejmowałyby co najmniej najważniejsze aktualizacje wizualne, takie jak animacje. Może się to jednak zdarzyć tylko wtedy, gdy animacje są obsługiwane przez wątek kompozytora.

Brakujące aktualizacje farb

Innym rodzajem aktualizacji częściowej jest sytuacja, gdy media, takie jak obrazy, nie zostały jeszcze zdekodowane i rasteryzowane na czas wyświetlania klatki.

Nawet jeśli strona jest całkowicie statyczna, przeglądarki mogą nie nadążać z renderowaniem zmian wizualnych podczas szybkiego przewijania. Dzieje się tak, ponieważ w celu oszczędzania pamięci GPU można odrzucić renderowanie pikseli treści znajdujących się poza widocznym obszarem. Renderowanie pikseli wymaga czasu, a renderowanie wszystkich elementów po przewinięciu dużej ilości danych, np. przesunięciu palcem, może zająć więcej niż 1 ramka. Jest to tak zwane przeplatanie.

W przypadku każdej możliwości renderowania klatki można śledzić, ile z najnowszych aktualizacji wizualnych rzeczywiście pojawiło się na ekranie. Pomiar możliwości wykonywania tej czynności w przypadku wielu klatek (lub w ciągu określonego czasu) jest powszechnie znany jako przepustowość klatek.

Jeśli procesor graficzny jest naprawdę przeciążony, przeglądarka (lub platforma) może ograniczyć częstotliwość prób aktualizacji wizualnych, co spowoduje zmniejszenie skutecznych częstotliwości klatek. Chociaż technicznie może to zmniejszyć liczbę utraconych aktualizacji klatek, wizualnie nadal będzie to wyglądać jak niższa przepustowość klatek.

Nie wszystkie typy niskiej przepustowości klatek są jednak złe. Jeśli strona jest w większości nieaktywna i nie ma aktywnych animacji, niska liczba klatek na sekundę jest tak samo atrakcyjna wizualnie jak wysoka liczba klatek na sekundę (a może też oszczędzać baterię).

Kiedy przepustowość klatek ma znaczenie?

Wykrywanie animacji

Wysoka przepustowość klatek ma znaczenie zwłaszcza w okresach ważnych animacji. Różne typy animacji zależą od wizualnych aktualizacji z konkretnego wątku (głównego, kompozytora lub wątku roboczego), więc ich aktualizacja zależy od tego, czy dany wątek zdąży je przekazać w określonym terminie. Mówimy, że dany wątek wpływa na płynność, gdy jest aktywna animacja, która zależy od aktualizacji tego wątku.

Niektóre typy animacji są łatwiejsze do zdefiniowania i wykrycia niż inne. Deklaratywna animacja lub animacja sterowana przez użytkownika jest łatwiejsza do zdefiniowania niż animacja sterowana przez JavaScript, która jest implementowana jako okresowe aktualizacje właściwości stylów do animowania.

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

Jakość a ilość

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

Podczas oglądania filmu możesz na przykład zobaczyć płynną liczbę klatek na sekundę wynoszącą 60. Technicznie jest to płynne, ale sam film może mieć niski bitrate lub problemy z buforowaniem w sieci. Dane te nie są rejestrowane bezpośrednio przez wskaźniki płynności animacji, ale mogą być irytujące dla użytkownika.

Zdarza się też, że gra, która korzysta z <canvas> (np. z technik takich jak pozaekranowa kanwa, aby zapewnić płynną animację), może technicznie wyświetlać płynne klatki animacji, ale nie wczytywać do sceny zasobów o wysokiej jakości lub generować artefaktów podczas renderowania.

Oczywiście w witrynie mogą też występować źle animowane elementy.

GIF z przedszkola w trakcie budowy

Chyba były fajne jak na swoje czasy.

Stany pojedynczej klatki animacji

Ponieważ klatki mogą być wyświetlane częściowo lub mogą być pomijane w sposób, który nie wpływa na płynność, zaczęliśmy traktować każdą klatkę jako całość lub całość z oceny płynności.

Oto zakres sposobów, w jaki interpretujemy stan pojedynczego klatki animacji, w kolejności od najlepszego do najgorszego:

Nie potrzebuję aktualizacji Czas bezczynności, powtórzenie poprzedniej klatki.
Pełna prezentacja Aktualizacja wątku głównego została zatwierdzona w terminie lub nie była potrzebna.
Częściowo zaprezentowana Tylko kompozytor; opóźniona aktualizacja głównego wątku nie spowodowała żadnych zmian wizualnych.
Częściowo zaprezentowana Tylko kompozytor; wątek główny został zaktualizowany wizualnie, ale ta aktualizacja nie zawierała animacji, która wpływa na płynność.
Częściowo zaprezentowana Tylko kompozytor: wątek główny zawierał aktualizację wizualną, która wpływa na płynność, ale zamiast tego została użyta nieaktualna migawka.
Częściowo zaprezentowana Tylko kompozytor; bez pożądanej głównej aktualizacji, a kompozytor ma animację, która wpływa na płynność.
Częściowo zaprezentowana Tylko kompozytor, ale aktualizacja kompozytora nie zawiera animacji, która wpływa na płynność.
Pominięta klatka Brak aktualizacji. Nie było potrzeby aktualizowania kompozytora, a główny kod został opóźniony.
Pominięta klatka Pożądana była aktualizacja kompozytora, ale została opóźniona.
Nieaktualna klatka Pożądana była aktualizacja, została ona wygenerowana przez renderer, ale GPU nie wyświetlił jej przed terminem synchronizacji pionowej.

Można je przekształcić w swego rodzaju wynik. Jednym z możliwych sposobów interpretacji tego wyniku jest użycie go jako prawdopodobieństwo, że użytkownik zauważył reklamę. Pojedyncze utracone klatki mogą nie być bardzo widoczne, ale sekwencja wielu utraconych klatek, które wpływają na płynność, na pewno jest.

Łączenie wszystkich danych: wskaźnik odsetek utraconej liczby klatek

Czasami konieczne jest dokładne zbadanie stanu każdego klatki animacji, ale przydatne jest też przypisanie szybkiego wyniku „na pierwszy rzut oka” dla danego doświadczenia.

Ponieważ klatki mogą być częściowo wyświetlane, a nawet całkowicie pominięte aktualizacje klatek mogą nie wpływać na płynność, chcemy skupić się nie tylko na zliczaniu klatek, ale też na sposobie, w jaki przeglądarka nie może zapewnić pełnych aktualizacji w ważnych momentach.

Model mentalny powinien przejść od:

  1. Liczba klatek na sekundę to
  2. wykrywanie brakujących i ważnych aktualizacji animacji, aby
  3. Odsetek odrzuconych w określonym okresie.

Liczy się proporcja czasu oczekiwania na ważne aktualizacje. Uważamy, że jest to zgodne z naturalnym sposobem, w jaki użytkownicy doświadczają płynności treści internetowych w praktyce. Do tej pory jako początkowy zestaw danych używaliśmy tych danych:

  • Średni odsetek opuszczonych klatek: dotyczy wszystkich klatek animacji, które nie są w stanie bezczynności w trakcie całej osi czasu.
  • Najgorszy przypadek odsetka utraconej liczby klatek: zmierzony w przesuwających się oknach czasowych o długości 1 sekundy.
  • 95 percentyl liczby utraconych klatek: mierzony w oknach czasowych o długości 1 sekundy.

Obecnie można je znaleźć w niektórych narzędziach deweloperskich w Chrome. Te dane dotyczą tylko ogólnego przepływu danych, ale bierzemy pod uwagę też inne czynniki, takie jak opóźnienie klatek.

Wypróbuj to w narzędziach dla deweloperów.

Wyświetlacz HUD

Chromium ma ukryty za flagą (chrome://flags/#show-performance-metrics-hud) skrót Performance HUD, w którym znajdziesz na żywo wyniki dotyczące m.in. podstawowych wskaźników internetowych oraz kilka eksperymentalnych definicji płynności animacji na podstawie odsetek utracone ramki na przestrzeni czasu.

Wyświetlacz HUD

Statystyki renderowania klatek

Włącz „Statystyki renderowania klatek” w DevTools, aby zobaczyć na żywo nowe klatki animacji, które są oznaczone kolorami w celu odróżnienia częściowych od pełnych aktualizacji. Podawana liczba klatek na sekundę dotyczy tylko w pełni wyświetlonych klatek.

Statystyki renderowania klatek

Podgląd klatek w nagraniach profilu wydajności w Narzędziach deweloperskich

Panel wydajności w Narzędziach deweloperskich zawiera od dawna przeglądarkę 帧. Jednak nie do końca pasuje do współczesnego procesu renderowania. Ostatnio wprowadziliśmy wiele ulepszeń, które są dostępne nawet w najnowszej wersji Chrome Canary. Uważamy, że znacznie ułatwią one debugowanie problemów z animowaniem.

Obecnie klatki w przeglądarce klatek są lepiej dopasowane do granic synchronizacji pionowej i oznaczone kolorami na podstawie stanu. Całkowita wizualizacja nie obejmuje jeszcze wszystkich opisanych powyżej niuansów, ale w najbliższej przyszłości planujemy dodać więcej funkcji.

Wyświetlacz ramki w narzędziach deweloperskich w Chrome

Śledzenie w Chrome

Na koniec warto wspomnieć o Chrome Tracing, czyli narzędziu, które pozwala zagłębić się w szczegóły. Za jego pomocą możesz rejestrować ślad „Renderowanie treści internetowych” za pomocą nowego interfejsu Perfetto (lub about:tracing) i głębiej analizować ścieżkę przetwarzania grafiki w Chrome. Może to być trudne zadanie, ale w ostatnim czasie do Chromium dodano kilka funkcji, które ułatwiają to zadanie. Informacje o dostępnych opcjach znajdziesz w dokumentie Cykl życia ramki.

Dzięki zdarzeniom z wykresu możesz jednoznacznie określić:

  • które animacje są odtwarzane (za pomocą zdarzeń o nazwie TrackerValidation);
  • Pobieranie dokładnej osi czasu klatek animacji (za pomocą zdarzeń o nazwie PipelineReporter).
  • W przypadku płynnych animacji aktualizacji dowiedz się, co dokładnie uniemożliwia animacji szybsze działanie (za pomocą podziału zdarzeń w ramach zdarzeń PipelineReporter).
  • W przypadku animacji sterowanych danymi wejściowymi sprawdź, ile czasu zajmuje aktualizacja wizualna (za pomocą zdarzeń o nazwie EventLatency).

Raportowanie śledzenia Chrome

Co dalej?

Inicjatywa wskaźników internetowych ma na celu zapewnienie danych i wskazówek dotyczących tworzenia wrażeń w internecie. Dane laboratoryjne, takie jak Total Blocking Time (TBT), są niezbędne do wykrywania i diagnozowania potencjalnych problemów z interakcją. Planujemy zaprojektować podobne dane laboratoryjne dotyczące płynności animacji.

Będziemy Cię informować o naszych postępach w pracy nad pomysłami na opracowanie kompleksowych danych na podstawie informacji o poszczególnych klatkach animacji.

W przyszłości chcemy też opracować interfejsy API, które umożliwią skuteczne pomiary płynności animacji w przypadku rzeczywistych użytkowników w warunkach rzeczywistych, a także w laboratorium. Bądź na bieżąco z informacjami na ten temat.

Prześlij opinię

Cieszymy się z ostatnich ulepszeń i narzędzi dla deweloperów w Chrome, które umożliwiają pomiar płynności animacji. Wypróbuj te narzędzia, porównaj swoje animacje i daj nam znać, do czego to prowadzi.

Komentarze możesz wysyłać do grupy Google web-vitals-feedback, wpisując w polu tematu „[Gładkość]”. Czekamy na Twoją opinię.