Статьи

Введение в аппаратное ускорение с помощью анимации CSS

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

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

Почему это должно меня волновать?

Давайте рассмотрим простой пример анимации, содержащий несколько шариков, расположенных друг над другом (то есть на оси z, поэтому он выглядит как один шарик). Цель состоит в том, чтобы переместить эту группу шаров с анимацией. Самый простой способ сделать это – настроить свойства lefttop Мы могли бы сделать это с помощью JavaScript, но вместо этого мы будем использовать CSS-анимацию. Обратите внимание, что я исключаю префиксы поставщиков, но вы должны использовать что-то вроде Autoprefixer для обеспечения полной совместимости.

 .ball-running {
  animation: run-around 4s infinite;
}

@keyframes run-around {
  0%: {
    top: 0;
    left: 0;
  }

  25% {
    top: 0;
    left: 200px;
  }

  50% {
    top: 200px;
    left: 200px;
  }

  75% {
    top: 200px;
    left: 0;
  }
}

Вот живая демонстрация, которая использует кнопку для запуска анимации с помощью JavaScript:

Нажав кнопку «Начать анимацию», вы заметите, что анимация выглядит не очень плавно даже в браузере настольного компьютера. Если вы протестируете анимацию на своем мобильном устройстве, вы увидите, что она далека от 60 кадров в секунду. Чтобы исправить это, мы можем использовать CSS-преобразование с помощью функции translate()topleft

 .ball-running {
  animation: run-around 4s infinite;
}

@keyframes run-around {
  0%: {
    transform: translate(0, 0);
  }

  25% {
    transform: translate(200px, 0);
  }

  50% {
    transform: translate(200px, 200px);
  }

  75% {
    transform: translate(0, 200px);
  }
}

Попробуйте приведенный выше код в демоверсии ниже:

Теперь анимация приятная и плавная. Большой! Так почему это помогло? Что ж, CSS-преобразования не вызывают перерисовки, в отличие от анимации со свойствами lefttop Давайте посмотрим на панель временной шкалы в Chrome DevTools во время выполнения анимации:

Временная шкала DevTools во время анимации с левой и верхней

В lefttop Это дорогостоящая операция перекраски. Частота кадров анимации составляет менее 60 кадров в секунду, чего мы всегда стремимся добиться, чтобы анимация была плавной.

Теперь рассмотрим временную шкалу в случае CSS-преобразований:

DevTools Timeline во время анимации с CSS-преобразованием

Как видите, во время анимации зеленых полос нет.

Еще одна функция, доступная в Chrome DevTools для отслеживания процесса перекраски, – «Включить мигание краски». Вы можете найти эту опцию, открыв DevTools, нажав клавишу ESC, а затем выбрав вкладку «Рендеринг». Когда эта функция включена, вокруг перекрашенных областей появятся зеленые прямоугольники (например, нарисованные прямоугольники). В lefttop

Показать рисование прямоугольников во время анимации с левой и верхней

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

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

Как работает аппаратное ускорение

Когда браузер получает разметку страницы, он анализирует ее для построения дерева DOM. Дерево DOM и CSS позволяют браузеру создавать дерево рендеринга. Дерево рендеринга состоит из объектов рендеринга – элементов, которые будут отображаться на странице. Каждый объект рендеринга назначается графическому слою. Каждый слой загружается в графический процессор в виде текстуры. Хитрость в том, что слой можно преобразовать в графическом процессоре без перерисовки, как в случае с трехмерной графикой. Эти преобразования выполняются отдельным процессом Compositor. Вы можете найти больше информации о композиции в Chrome здесь .

В нашем примере преобразование CSS создает новый составной слой, который можно преобразовать непосредственно в графическом процессоре. DevTools в Chrome позволяют просматривать составные слои с помощью параметра «Показать границы слоев». Каждый композитный слой имеет оранжевую рамку.

Наши шары с преобразованием CSS имеют оранжевые границы и перемещаются в отдельные составные слои:

Показать границы слоя во время анимации с помощью CSS трансформации

В этот момент вы можете спросить: когда браузер создает отдельный составной слой?

Это происходит в следующих случаях:

  • Для 3D или перспективных CSS-преобразований (в нашем примере)
  • Для элементов <video><canvas>
  • При использовании фильтров CSS
  • Для элемента, который перекрывает другой элемент, извлеченный в составной слой (например, с использованием z-index

Вы можете подумать: «Держись. В этом примере использовался 2D-перевод, а не 3D-преобразования. И ты прав. Вот почему в нашей временной шкале есть две дополнительные операции перерисовки – в начале и в конце процесса анимации.

2D трансформации CSS инициируют перерисовку до и после анимации

Разница между 3D и 2D-преобразованиями заключается в том, что 3D-преобразования заставляют браузер заранее создавать отдельный составной слой, в то время как 2D-преобразования делают это на лету. В начале анимации создается новый составной слой, и текстуры загружаются в графический процессор, что инициирует перерисовку. Затем анимация выполняется Композитором в графическом процессоре. Когда анимация заканчивается, дополнительный составной слой удаляется, что приводит к другой операции перекраски.

Элементы рендеринга в GPU

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

  • transform
  • opacity
  • filter

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

Принудительное отображение элемента в графическом процессоре

В некоторых случаях может потребоваться визуализировать элемент в графическом процессоре даже до начала анимации. Это помогает избежать первой операции перекраски, вызванной созданием нового слоя. Для этого может пригодиться так называемое «преобразование взломать».

 .example1 {
  transform: translateZ(0);
}

.example2 {
  transform: rotateZ(360deg);
}

Это дает браузеру понять, что мы хотим выполнить 3D-преобразование. Это заставляет браузер создавать отдельный слой и заранее перемещать элемент в графический процессор, вызывая аппаратное ускорение.

Этот метод также может быть полезен, когда перерисовка одного элемента слишком дорога из-за другого элемента позади него. Давайте вернемся к первому примеру и немного изменим его, чтобы он содержал один шарик и контейнер с фоновым изображением, размытым с помощью фильтров CSS. Шар анимирован с lefttop

Опять же, движение мяча отрывистое. Это происходит потому, что каждая операция перерисовки стоит слишком дорого из-за размытого фона.

Теперь давайте добавим хак с преобразованием в контейнер.

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

Используйте аппаратное ускорение с осторожностью

Ничто не приходит бесплатно. Есть некоторые проблемы, связанные с аппаратным ускорением.

Память
Самая важная проблема связана с памятью. Загрузка слишком большого количества текстур в графический процессор может вызвать проблемы с памятью. Это очень важно для мобильных устройств и может даже вызвать сбой мобильного браузера. Помните о последствиях и не используйте аппаратное ускорение для каждого элемента на странице.

Рендеринг шрифта
Рендеринг в GPU влияет на сглаживание шрифтов. Это происходит потому, что GPU и CPU имеют разные механизмы рендеринга. Таким образом, даже если вы отключите аппаратное ускорение в конце анимации, текст будет отображаться размытым во время анимации. Вы можете прочитать больше о проблемах рендеринга шрифтов в этом посте Китом Кларком .

Ближайшее будущее

Необходимость использовать «преобразование взломать» для создания отдельных составных слоев является громоздким. Браузеры определенно должны предоставить простой способ сделать это. Вот почему было введено свойство will-change . Эта функция позволяет вам сообщать браузеру, какое свойство будет изменено, поэтому браузер может сделать соответствующие оптимизации заранее. Вот пример, который сообщает браузеру, что свойство transform

 .example {
  will-change: transform;
}

К сожалению, не все браузеры поддерживают изменения . Вы можете узнать больше об will-change

Вывод

Подводя итог, что мы рассмотрели:

  • Использование GPU может улучшить качество вашей анимации
  • Анимация с графическим процессором должна быть 60fps на каждом устройстве
  • Используйте GPU-дружественные свойства CSS
  • Понять, как заставить элемент отображаться в графическом процессоре, используя «преобразование взломать».

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