1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
---
title: Производительность CSS и JavaScript анимации
slug: Web/Performance/CSS_JavaScript_animation_performance
tags:
- CSS
- FPS
- Transitions
- requestAnimationFrame
- Анимация
- Производительность
translation_of: Web/Performance/CSS_JavaScript_animation_performance
---
<p class="summary">Анимация является критичным инструментом для улучшения пользовательского опыта во многих приложениях. Существует много путей создания анимации в web, например, основанные на CSS-свойствах {{cssxref("transition","transitions")}}/{{cssxref("animation","animations")}} или на JavaScript (using {{domxref("Window.requestAnimationFrame","requestAnimationFrame()")}}). В этой статье мы проанализируем производительность CSS и JavaScript анимаций и сравним их.</p>
<h2 id="CSS_transition_и_animation">CSS transition и animation</h2>
<p>Оба этих свойства могут использоваться для создания анимации. Каждое из них имеет своё специфичное назначение:</p>
<ul>
<li>CSS {{cssxref("transition","transitions")}} предоставляет простой способ создать анимацию, которая происходит при переходе от текущего состояния к конечному, например, переход от обычной кнопки к кнопке в состоянии hover. Даже если элемент в середине перехода от одного стиля к другому, новый эффект transition стартует немедленно, вместо того, чтобы дожидаться, пока запущенный ранее эффект завершится. Подробнее здесь: <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_transitions">Использование CSS transitions</a>.</li>
<li>CSS {{cssxref("animation","animations")}}, с другой стороны, позволяет разработчикам создавать анимацию, основанную на ключевых кадрах (keyframes), которые указывают этапы, которые должна пройти анимация от начального до финального состояния. CSS animation состоит из двух компонент: описание свойства, которое указывает на анимацию, а так же набор ключевых кадров, которые указывают начальное, финальное и промежуточные состояния элемента. Подробнее здесь: <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Using_CSS_animations">Использование CSS animations</a>.</li>
</ul>
<p>Если говорить о производительности - между этими двумя подходами нет разницы. Оба подхода основаны на одном и том же механизме, которые описаны далее.</p>
<h2 id="requestAnimationFrame">requestAnimationFrame</h2>
<p>API {{domxref("Window.requestAnimationFrame","requestAnimationFrame()")}} предоставляет эффективный способ создания анимаций в JavaScript. Функция (callback), которую вы передаёте в этот метод, будет вызываться перед каждой следующей отрисовкой нового фрейма. Главное отличие от {{domxref("WindowTimers.setTimeout","setTimeout()")}}/{{domxref("WindowTimers.setInterval","setInterval()")}} в том, что здесь вам не нужно указывать время, через которое функция запустится. <code>requestAnimationFrame()</code> работает гораздо эффективнее, учитывая частоту кадров и производительность системы. Разработчики могут создавать анимацию, просто изменяя стили элемента каждый раз, когда происходит подготовка нового кадра (или когда обновляется полотно Canvas или в других случаях).</p>
<div class="note">
<p><strong>Примечание</strong>: Подобно CSS transition и animation, <code>requestAnimationFrame()</code> приостанавливает работу, когда текущий таб переводится в фоновый режим (например, при смене фокуса)</p>
</div>
<p>Для подробностей ознакомьтесь с <a href="https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/">анимирование с JavaScript: от setinterval до requestAnimationFrame</a>.</p>
<h2 id="Сравнение_производительности_transitions_и_requestAnimationFrame">Сравнение производительности:<br>
transitions и requestAnimationFrame</h2>
<p>По факту, в большинстве случаев, производительность анимаций CSS практически идентична анимациям на JavaScript. По крайней мере в Firefox. Авторы некоторых JavaScript библиотек для анимации, например GSAP или Velocity.JS, даже берутся утверждать, что их решения могут работать быстрее, чем аналогичные решения на CSS. Такое возможно, потому что CSS transitions/animations просто заново вычисляют стили элементов в основном потоке процессора сразу перед тем, как срабатывает событие repaint, что примерно то же самое, что вычислять стили заново с помощью <code>requestAnimationFrame()</code>. Если обе анимации выполняются в одном потоке, то разницы в производительности не будет.</p>
<p>В следующей секции мы пройдёмся по тестам производительности, используя Firefox, чтобы увидеть, какие методы анимации работают эффективнее.</p>
<h3 id="Включение_измерения_частоты_кадров_FPS">Включение измерения частоты кадров FPS</h3>
<p>Для начала нам нужно включить инструменты измерения частоты кадров (FPS Tools), чтобы иметь возможность видеть текущую частоту кадров</p>
<ol>
<li>В поле ввода URL наберите <em>about:config</em>; Нажмите на кнопку <em>I’ll be careful, I promise!, чтобы войти на страницу конфигурации</em>.<br>
<img alt="" src="https://mdn.mozillademos.org/files/11137/Pic1.png" style="height: 349px; width: 600px;"><br>
</li>
<li>В поле поиска введите <code>layers.acceleration.draw-fps</code>.</li>
<li>Нажмите два раза на ячейку, чтобы присвоить значение <code>true</code>. Теперь вы видите три розовых блока в верхнем левом углу окна. Первый блок указывает FPS.<br>
<img alt="" src="https://mdn.mozillademos.org/files/11139/Pic2.png" style="height: 215px; width: 562px;"></li>
</ol>
<h3 id="Запуск_теста">Запуск теста</h3>
<p>Для начала, в нашем тесте мы будем анимировать 1000 элементов {{htmlelement("div")}} с помощью CSS.</p>
<p><span style="line-height: 16.7999992370605px;">{{JSFiddleEmbed("https://jsfiddle.net/zt94oew2/1/","","480")}}</span></p>
<p>Нажав на кнопку, вы можете переключить метод анимации на <code>requestAnimationFrame()</code>.</p>
<p>Попробуйте запустить оба метода и сравнить FPS. Скорее всего, вы увидите, что частота кадров отличается - анимации с CSS заметно быстрее. В следующей главе мы разберём - почему.</p>
<h3 id="Анимация_вне_основного_потока_процесса">Анимация вне основного потока процесса</h3>
<p>Браузерный JavaScript является строго однопоточным языком, то есть он не может одновременно работать над двумя задачами. В этом кроется проблема анимации с помощью JavaScript. Выполняя такую анимацию, вы занимаете процессор, который мог бы в это время заниматься другими функциями. В противоположность этому, CSS-анимации могут быть выделены в отдельный поток, то есть при выполнении таких анимаций браузер не блокирует выполнение других процессов. </p>
<p>Для того, чтобы выделить анимацию CSS в отдельный процесс, нам нужно убедиться, что изменяемые свойства не запускают этапы reflow/repaint (подробнее здесь: <a href="http://csstriggers.com/">CSS triggers</a>). Если изменяемые CSS-свойства не делают этого, то мы можем вынести операции по вычислению стилей в отдельный поток. Наиболее известное свойство - это CSS Transform, которое выводит элемент в отдельный <a href="https://wiki.mozilla.org/Gecko:Overview#Graphics">слой</a>. Если элемент представляет из себя отдельный слой, то вычисление каждого следующего кадра может быть сделано на графическом процессоре (GPU). Это радикально улучшает производительность, особенно на мобильных устройства. Подробности здесь: <a href="https://wiki.mozilla.org/Platform/GFX/OffMainThreadCompositing">OffMainThreadCompositing</a>.</p>
<p>Вы можете отключить выведение анимации в отдельный поток, чтобы посмотреть, как эта особенность влияет на FPS. Для этого в настройках Firefox найдите флаг <code>layers.offmainthreadcomposition.async-animations</code>. И переключите его в <code>false</code>.</p>
<p><img alt="" src="https://mdn.mozillademos.org/files/11141/Pic3.png" style="height: 210px; width: 536px;"></p>
<p>После выключения этой опции вы увидите, что FPS при использовании CSS стал таким же, как и при использовании JS.</p>
<h2 id="Итог">Итог</h2>
<p>Браузеры способы оптимизировать рендеринг не только программно, но и аппаратно. В целом, вам нужно стараться использовать CSS transitions/animations везде, где это возможно. Если же ваши анимации действительно сложны - помните, что писать анимацию на JavaScript нужно только с использованием <code>requestAnimationFrame()</code> .</p>
|