Производительность CSS-анимаций и переходов: под капотом браузера

Это перевод статьи из блогов Adobe.

Вероятно, Вы уже использовали CSS-анимации и переходы в своих проектах (а если ещё нет, то ознакомиться с ними Вы можете по ссылкам: animations, transitions). Так же, вероятно Вы сталкивались с тем, что некоторые из анимаций проходят плавно, а некоторые “идут рывками”. Есть идеи, почему?

В этой статье мы исследуем, как браузеры обрабатывают CSS-анимации и переходы, а в результате Вы сможете интуитивно (еще до написания кода) догадываться, в каких случаях анимация будет плавной, а в каких вместо плавной анимации будет “слайд-шоу”.

Под капотом браузера

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

Современные браузеры обычно имеют два потока, работающих совместно над отображением страницы:

  • основной поток;
  • выводящий (compositor) поток.

Как правило, основной поток ответственнен за:

  • исполнение JavaScript-кода;
  • расчет стилей элементов;
  • размещение элементов на странице;
  • отрисовку элементов в одно или несколько растровых изображений;
  • отрисовку отрисованных растровых изображений с помощью выводящего потока.

В то время, как выводящий поток ответственнен за:

  • отрисовку растровых изображения с помощью GPU;
  • опрос главного потока об обновлении растровых изображений видимых в данный момент или в ближайшем будущем частей страницы;
  • определение видимых частей страницы;
  • определение частей страницы, которые скоро станут видимыми, когда страница перематывается (скроллится);
  • перемещение частей страницы во время перемотки (скроллинга) страницы.

Основной поток может быть занят довольно долго, например, когда он исполняет JavaScript или отрисовывает в изображение большой элемент. Пока основной поток занят, он не способен отвечать на пользовательский ввод.

С другой стороны – выводящий поток является очень отзывчивым к пользовательскому вводу. Он пытается перерисовать страницу 60 раз в секунду когда она изменяется, даже в том случае, когда страница ещё не завершена.

Например, когда пользователь перематывает страницу, выводящий поток запрашивает у основного обновление изображений (растров) элементов, которые будут отображены. Если основной поток не отвечает достаточно быстро, то выводящий поток не ожидает его. Выводящий поток отрисовывает готовые растровые изображения или заливку белым, если изображения требуемой области страницы ещё не готовы.

GPU

Как уже было сказано, выводящий поток отрисовывает изображения на экран используя GPU – графический процессор.

GPU – чип, использующийся в большинстве телефонов, планшетов и компьютеров. GPU довольно узко специализирован: он отлично справляется с некоторыми задачами, но не так хорош в остальных.

В частности, GPU очень быстр в:

  • отрисовке на экран;
  • отрисовке на экран одного изображения несколько раз;
  • отрисовке на экран одного изображения в различных позициях, под разными углами или в различных масштабах.

Но GPU относительно медлителен в:

  • загрузке изображений в свою память.

Анимация перехода: свойство «height»

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

Предположим, что анимация перехода определена изменением высоты элемента от 100 до 200 пикселей:

div {
    height: 100px;
    transition: height 1s linear;
}
 
div:hover {
    height: 200px;
}

Основной поток и отображающий поток производят операции в соответствии с временной диаграммой описанной ниже. Операции в оранжевых блоках потенциально медленные. Операции в синих блоках – быстрые.


Как можно заметить, на диаграмме присутствует множество оранжевых блоков, а это означает то, что браузеру придется потрудится над выполнением задачи, а переход, в свою очередь, будет выполнен рывками.

Для каждого кадра анимации перехода браузер:

  • располагает элементы на странице;
  • отрисовывает страницу или её часть в изображение;
  • загружает изображения в память GPU.

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

Анимация перехода: свойство «transform»

Анимирование изменения свойства height может быть достаточно дорогой операцией. Есть ли другой, более дешевый способ анимирования?

Предположим, мы масштабируем элемент из сжатого в 2 раза в полноразмерный. Так же, предположим, что мы используем CSS-свойство transform для масштабирования и свойство transition для определения анимации перехода:

div {
    transform: scale(0.5);
    transition: transform 1s linear;
}
 
div:hover {
    transform: scale(1.0);
}

Взглянем на времменную диаграмму для этого варианта:

В этот раз на диаграмме намного меньше оранжевых блоков, а это означает, что анимация вероятно будет плавной! Но в чем отличие анимирования изменения свойства высоты элемента от анимирования изменения свойства трансформации элемента?

По определению, CSS-свойство transform не затрагивает дочерние элементы или элементы вокруг анимируемого. Оно влияет на элемент целиком – масштабирует, поворачивает или перемещает элемент “как есть”.

Для браузера это отличные новости! Браузеру нужно только сгенерировать изображение для элемента и загрузить его в память графического процессора один раз – перед началом анимации. После, браузер больше не выполняет размещение элементов, не отрисовывает элементы в изображения и не отправляет их в память GPU. Вместо этого, браузер может управлять специальными возможностями GPU: повторной отрисовкой изображения на экране, отрисовкой изображения в произвольном месте, поворотом и масштабированием изображения.

Выбор анимации

Значит ли это, что использовать анимацию перехода для CSS-свойства height – плохо? Нет. Иногда такая анимация будет работать достаточно быстро. Возможно, анимируемые элементы изолированы, а их анимация не приведет к перерисовке соседних элементов. Возможно, анимируемые элементы достаточно просто перерисовать и браузер сможет сделать это быстро. Возможно, анимируемые элементы достаточно малы и загрузка их отрисовок в память GPU будет быстрой.

Конечно, если у Вас есть возможность анимировать “дешевые” css-свойства вместо “дорогих”, вроде height и это не повлияет на ваш дизайн, то сделайте такую замену. Например, пусть есть кнопка, которая отображает меню, когда нажата. Вместо анимирования свойств top и height для раскрытия меню, попробуйте анимировать свойство transform для получения такого же эффекта.

В современных браузерах сравнительно быстро анимируются следующие CSS-свойства:

В настроящий момент этот список достаточно ограничен, но вместе с развитием браузеров все больше css-свойств будут становиться быстро-анимируемыми.

Возможно, вы будете удивлены, как много интересных эффектов можно создать, комбинируя эти свойства. Будте креативнее!

1 thought on “Производительность CSS-анимаций и переходов: под капотом браузера

Leave a Reply

Your email address will not be published.