[Перевод] Анализ производительности CSS-анимаций

Что выбрать для анимирования элементов веб-страниц? JavaScript или CSS? Этот вопрос однажды вынужден будет задать себе каждый веб-разработчик. А может — и не однажды.

JavaScript-программисты создали множество библиотек для браузерной анимации. И, похоже, все вокруг оказались склонны к тому, чтобы использовать эти библиотеки в виде готового решения для анимации. Но давайте-ка притормозим. Правильно ли это? Следует ли анимировать элементы веб-страниц с помощью JavaScript? Может, можно положиться на стандартные механизмы CSS и добиться тем самым качественной и высокопроизводительной анимации?

dedpjvqp7lfw3cyv961zhombmv8.png

Так как вы это читаете, я могу предположить, что вы знакомы с JavaScript-анимацией. Поэтому предлагаю исследовать тему CSS-анимации в разных её проявлениях, а так же — предлагаю поговорить о производительности такой анимации.

Общие сведения


Анимация в CSS основана на некоторых свойствах элементов. Среди них можно отметить следующие:

  • Свойство position, которое, в частности, может принимать значения absolute и relative.
  • Свойство transform.
  • Свойство opacity.
  • Свойства left, right, top, bottom.


Для начала взглянем на пару экспериментальных проектов, в которых для анимирования элементов используются различные CSS-свойства.

Вот проект, в котором анимируется элемент с идентификатором animate, свойство которого position установлено в значение absolute. Изменениям подвергаются свойства элемента top и left.

767eca9be9e90e189241b4b105e50e32.png


Страница экспериментального проекта

Ниже показан код, который реализует эту анимацию.

#animate {
    position: absolute;
    top: 100px;
    left: 30px;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: red;

    animation: move 3s ease infinite;
}

@keyframes move {
    50% {
        top: 200px;
        left: 130px;
    }
}


Вот проект, в котором такая же анимация реализована с помощью CSS-свойства transform.

Эта анимация представлена следующим кодом:

#animate {
    position: absolute;
    top: 100px;
    left: 30px;
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background: red;

    animation: move 3s ease infinite;
}

@keyframes move {
    50% {
        transform: translate(100px, 100px);
    }
}


Давайте воспользуемся этими проектами для того чтобы сделать выводы о производительности CSS-анимаций, и о том, какие именно ресурсы системы используются для их реализации.

Если просто посмотреть на страницы проектов — можно решить, что реализовано в них одно и то же, хоть и с использованием различных подходов. Однако если измерить показатели производительности этих проектов с использованием инструментов разработчика Chrome, то окажется, что они отличаются.

Как браузер выводит страницу?


Прежде чем мы углубимся в исследование производительности, нам нужно понять то, как браузер выводит страницу, и то, какие действия он выполняет в том случае, если на странице происходят какие-то изменения.

Вот как выглядит процесс вывода страницы.

8c14ace8bee309b48437d1a8aa951964.png


Вывод страницы

Рассмотрим события, которые отражены на этом рисунке.

  1. Recalculate Style — вычисление стилей, которые будут применены к элементам.
  2. Layout — создание макетов элементов и их размещение на странице.
  3. Paint — заполнение пикселей созданных слоёв, то есть — создание растровых изображений для каждого слоя. GPU будет использовать эти изображения для вывода страницы на экран.
  4. Composite Layer — компоновка слоёв и вывод их на экран. То, что получится в результате, и будет готовой страницей.


Событие Composite Layer — это как раз то время, когда CPU обменивается данными с GPU для создания анимации. Используя CSS-свойства вроде transform и opacity, мы можем перенести нагрузку по формированию анимации с CPU на GPU.

Анимация и GPU


GPU — это, по сути, специализированный компьютер, используемый для работы с изображениями. Он может эффективно обрабатывать большие объёмы графической информации.

В результате, когда происходит событие Composite Layer, создаётся дополнительный слой. Это — механизм, благодаря которому можно избежать повторного рендеринга анимированного элемента и других элементов интерфейса.

Глядя на следующий рисунок, можно подумать о том, что анимированные элементы расположены на одном и том же слое.

3e2d98a7d49fa60ad88d0bcdeafaa57f.png


Анимированные элементы (оригинал)

Но если взглянуть на слои так, будто они расположены в трёхмерном пространстве, окажется, что при реализации анимации с помощью свойства transform для красного круга создаётся дополнительный слой. Это даёт возможность вывода высокопроизводительной плавной анимации.

2f4f999a23d5c79f96995139f8784d48.png


Для анимированного объекта создан дополнительный слой (оригинал)

GPU держит дерево рендеринга объектов в памяти, и, не выполняя повторного рендеринга, может поместить соответствующий слой поверх других слоёв. В случае же анимирования объекта с использованием свойств top и left, тот же слой, из-за изменения свойств, рендерится снова и снова. Если поинтересоваться особенностями поведения этих CSS-свойств, то окажется, что top и left воздействуют на макет страницы, что приводит к необходимости выполнения повторной отрисовки страницы и повторной компоновки слоёв.

d01a951ce13a60204a9e508fed6854a6.gif


Анимация с использованием свойства translate и с использованием свойств top и left

Этот рисунок позволяет увидеть серьёзное отличие между анимацией, реализованной с помощью свойства translate и свойств top и left.

В случае с анимацией, созданной с помощью top и left, круг рендерится в каждой позиции до тех пор, пока не достигнет крайнего положения. После этого он начинает двигаться к исходному положению.

Ниже показана панель Performance инструментов разработчика Chrome со сведениями о процессе анимации.

3274e4753958e7f5511dfa9d9cb8143e.png


Анимация с использованием свойства translate (оригинал)

921bbd4972cb948fa402a65dbbd60c30.png


Анимация с использованием свойств top и left (оригинал)

Если посмотреть подробные сведения об отдельных задачах, представленных в панели Performance, можно сделать вывод о том, что в рамках этих задач выполняются разные действия. Так, в случае с top/left-анимацией, в рамках задачи выполняется пересчёт стилей, компоновка слоёв, обновление дерева слоёв, создание макета и рендеринг. В случае с translate-анимацией единственная задача, решаемая GPU, заключается в перемещении слоя без вывода чего-либо в DOM.

В результате, за счёт применения мощных возможностей GPU, при использовании translate-анимации освобождается главный поток. Это способствует повышению производительности приложения. Применение top/left-анимации приводит к созданию большой дополнительной нагрузки на главный поток.

c6ecfb7bb152133d55a44362755b3e3b.png


Нагрузка на главный поток, создаваемая translate-анимацией (слева) и top/left-анимацией (справа) (оригинал)

Вышеприведённый рисунок наглядно демонстрирует ту нагрузку, которая ложится на главный поток при выполнении top/left-анимации. Это — результат постоянных изменений, которые необходимо обрабатывать для выполнения такой анимации.

Итоги


В результате можно сделать вывод о том, что, применяя CSS-анимации, стоит обращать внимание на то, какие именно ресурсы системы задействуются при их выполнении. По возможности стоит использовать те из них, которые выполняются средствами GPU.

А какие анимации вы используете в своих проектах?

a_bsaactpbr8fltzymtkhqbw1d4.png

© Habrahabr.ru