Слои анимации, и как их принудительно создать

Слои анимации, и как их принудительно создать

От автора: как создаются слои анимации? Ответ — will-change: transform. Или нет? Если только вы не будете изменять преобразование, не используйте will-change: transform. Используйте will-change: opacity или backface-visibility: hidden, поскольку их побочные эффекты, как правило, не вызывают столько проблем.

Общая информация

Очень упрощенный механизм рендеринга браузера выглядит следующим образом:

Загрузка и парсинг HTML, создание дерева DOM.

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

Изменение дерева макета в соответствии с инструкциями отображения, создавая «дерево отображения».

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

Выполнение всех этих инструкций отображения на этом холсте.

Эта работает отлично, пока вы не будете часто вводить изменения. Например, 60 раз в секунду. Если мы хотим, чтобы элемент вращался, мы не можем повторно использовать старый холст. Мы должны запустить обновление и вернуться к шагу 2.

Не было бы лучше, если бы мы нарисовали вращающийся элемент на прозрачной пленке? Таким образом, мы могли бы сохранить холст документа и повторно использовать его, отбросив только этот крошечный фрагмент пленки. Это то, что делают «слои».

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

Вы можете сделать слои видимыми через DevTools двумя способами:

Вы можете включить «Границы слоев» на вкладке «Рендеринг» в DevTool, и в результате увидите оранжевые границы вокруг элементов, расположенных в отдельном слое.

Через вкладку «Слои» в DevTools вы можете получить интерактивное представление в реальном времени всех слоев на текущей странице.

История

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

В прежние времена мы использовали следующий прием — устанавливали transform: translateZ(0). translateZ нужно использовать, чтобы применять графический процессор для вычисления искажения перспективы (даже если это в конечном итоге не будет искажением вообще). Если вы используете translateX или translateY, никаких искажений перспективы не требуется, и браузер будет отображать элемент в основном холсте, просто с указанными смещениями (демо).

Из-за того, что этот прием использовался для создания мерцания элемента в Chrome и Safari (это уже не так), рекомендовалось устанавливать для элементов backface-visibility: hidden — и этот совет по-прежнему приводится и по сей день.

В марте 2016 года iOS 9 получает поддержку свойства will-change, которое указывает браузеру, что определенное CSS-свойство … ну, изменится. Если вы установили для элемента will-change: transform, вы сообщаете браузеру, что свойство transform изменится в ближайшем будущем. В результате браузер может применять оптимизацию для учета этих будущих изменений. В случае преобразования это означает, что он выносит элемент в отдельный слой. Несмотря на то, что Edge не поддерживает will-change, оптимальной практикой стало считаться использовать will-change: transform, чтобы вынести элемент в отдельный слой. Архитектура Edge сильно отличается от Chrome, Firefox и Safari и позволяет выполнять эти виды анимаций без подсказки will-change.

Побочные эффекты

Что может быть не сразу очевидным, так это то, что все эти методы имеют побочный эффект, выраженный в разной степени.

backface-visbility

Как следует из названия, backface-visbility: hidden имеет побочный эффект, обратная сторона элемента скрывается. Обычно эта сторона не «обращена» к пользователю, но когда вы вращаете элементы в трехмерном пространстве, это может произойти. Если вы посмотрите эту демо-версию и нажмете кнопку “Flip boxes”, то увидите, что у элемента с backface-visibility: hidden обратная сторона скрыта.

will-change: transform

will-change: transform сообщает браузеру, что преобразование этого элемента изменится в ближайшем будущем. Для этой семантики спецификация предписывает, что параметр will-change: <something> должен иметь те же побочные эффекты, что и любое не начальное значение для свойства <something>.

Это кажется разумным, но могут возникнуть сложности при использовании position: fixed или position: absolute. Посмотрите эту демо-версию:

Если вы установите значение для transform, вы создадите так называемый новый «содержащий блок». Любые дочерние элементы с position: fixed или position: absolute теперь связаны с этим новым содержащим блоком, таким образом, как непоследовательное позиционирование розового блока в демо-версии. Это один из тех тонких побочных эффектов, которые, хотя и описаны в спецификации, на самом деле не слишком интуитивны, по моему мнению. Время от времени я спотыкаюсь об это.

transform: translateZ(0)

transform: translateZ(0) имеет те же побочные эффекты, что и change-transform: transform (он все-таки устанавливает преобразование), но также может мешать другим стилям, которые используют преобразование, поскольку эти свойства переписывают друг друга в соответствии с каскадом. Если вы посмотрите на обе предыдущие демо-версии, то увидите, что элементы, которые используют transform: translateZ(0), ведут себя не так, как ожидалось.

will-change: opacity

Если вы не обратили внимание, элемент с will-change: opacity, ведет себя в предыдущей демо-версии, как и ожидалось. Однако это не означает, что это побочный эффект. Задав will-change: opacity, мы создаем новый «стековый контекст». Это еще один термин из спецификации CSS, и, если по-простому, это означает, что он может повлиять на порядок отображения элементов. Если у вас есть перекрывающиеся элементы, это может изменить, какой элемент находится «поверх», как показано в этой демо-версии. Но даже если это произойдет, z-index поможет вам восстановить нужный порядок.

Мне не нравится will-change

На данном этапе мне не нравится will-change. Я думаю, что непрямой характер семантики, которую использует will-change, делает его чем-то вроде мистики или магии. То, что вы заявляете, на самом деле не говорит о том, чего вы хотите достичь. Объявляя эти свойства разработчики вовсе не хотят заявить «я изменю эти свойства» (и одновременно принимают все побочные эффекты). Они скорее хотят сказать что-то вроде «поместить это в отдельном слое» или «обрабатывать это как растровое изображение / текстуру». К сожалению, для таких объявлений пока ничего на горизонте не предвидится.

На данный момент у нас есть только will-change, и мой совет: используйте will-change: opacity или backface-visibility: hidden, чтобы вынести элемент в отдельный слой, поскольку при этом побочные эффекты с наименьшей вероятностью создадут проблемы. will-change: transform используйте только в том случае, если вы на самом деле собираетесь изменять преобразование.

Источник: https://dassur.ma/

Редакция: Команда webformyself.