Обеспечивает высокопроизводительную интерактивную анимацию со скоростью до 60 кадров в секунду.

внешний интерфейс JavaScript API браузер CSS
Обеспечивает высокопроизводительную интерактивную анимацию со скоростью до 60 кадров в секунду.

Оригинальная ссылка:Performant Web Animations and Interactions: Achieving 60 FPS

Примечание переводчика: в основном это старое клише, но есть и кое-что новое, смотрите в конце =)

Высокопроизводительная веб-интерактивная анимация: как добиться 60 кадров в секунду

Каждый продукт, который преследует естественные эффекты, надеется на плавный процесс взаимодействия. Тем не менее, разработчики могут игнорировать некоторые детали, что приводит к снижению производительности веб-анимации, что не только приводит к появлению «мусора на странице» (дерганье), но и самым прямым следствием является зависание страницы. Разработчики часто тратят много сил на оптимизацию загрузки первого экрана, на несколько миллисекунд, но игнорируют проблемы с производительностью, вызванные анимацией взаимодействия со страницей.

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

критерий успеха

Частоту кадров анимации можно использовать как меру общей картины. При частоте кадров 60 кадров в секунду результаты были лучше. Что такое преобразование, при котором каждый кадр выполняется за 16,7 мс (16,7 = 60/1000). Поэтому нашим приоритетом является снижение ненужных накладных расходов на производительность. Чем больше кадров нужно отрендерить, тем больше задач нужно решить, тем больше было вылетов из кадра, что является камнем преткновения для достижения 60 кадров в секунду. Если вы не можете завершить рендеринг всей анимации за 16,7 мс, лучше рассмотреть возможность рендеринга с немного меньшей частотой кадров — 30 кадров в секунду.

Браузер 101: как появился пиксель

首次页面加载时的 call tree

макет

Любые изменения макета являются дорогостоящими, и их следует избегать..

рисовать

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

сложный

Последний шаг — скомпоновать все нарисованные элементы. По умолчанию все элементы будут нарисованы в одном слое; если элементы разделены на разные составные слои, обновление элементов улучшит производительность, а элементы, которые не находятся в одном слое, не будут легко затронуты. ЦП рисует слой, а ГП генерирует слой. Основные операции рисования эффективно выполняются при компоновке с аппаратным ускорением. Разделение слоев позволяет вносить неразрушающие изменения, как нетрудно догадаться.Изменения на композитном слое графического процессора являются наименее дорогостоящими и имеют наименьшую стоимость производительности..

вдохновлять на творчество

Как правило, изменение составного слоя — это операция, требующая относительно небольшой производительности, поэтому старайтесь как можно больше изменять составной слой.opacityа такжеtransformЗначение запускает отрисовку составного слоя. Кажется... есть предел тому, что мы можем сделать, но так ли это на самом деле? Хорошо развивайте свои творческие способности.

трансформировать

«Преобразование» предоставляет неограниченные возможности для элемента: вы можете изменить положение (translateX, translateY, илиtranslate3d), размер также можно масштабировать (scale) изменять, но также вращать, наклонять и даже выполнять 3D-преобразование. То есть в некоторых сценариях разработчикам нужно думать по-другому и сокращать перекомпоновку и перерисовку с помощью преобразований. Например, после добавления имени активного класса к элементу он сдвинется на 10 пикселей влево.Вы можете изменить свойство left:

.box {
  position: relative;
  left: 0;
}
.active{
    left: -10px;
}

Вы также можете использовать что-то, что дает тот же эффект, но с большей производительностью.translate:

.active {
    transform: translateX(-10px);
}

прозрачность

Ты можешь изменитьсяopacitydisplayилиvisibilityopacityopacitypointer-eventsЗначение также следует изменить соответствующим образом, чтобы пользователь не мог работать с меню, которое явно скрыто. закрыто Имя класса будет добавлено в соответствии с тем, когда пользователь нажмет кнопку «открыть»; имя закрытого класса будет удалено, когда будет нажата кнопка «закрыть». Соответствующий код таков:

.menu {
  opacity: 1;
  transition: .2s;
}

.menu.closed {
  opacity: 0;
  pointer-events: none;
}

Кроме того, переменная прозрачность означает, что разработчики могут контролировать видимость элементов. Много думайте об использовании прозрачности — например, о прямых тенях на элементах (box-shadow) выполнение анимации может вызвать серьезные проблемы с производительностью:

.box {
    box-shadow: 1px 1px 1px rgba(0,0,0,.5);
    transition: .2s;
}
.active {
   box-shadow: 1px 1px 1px rgba(0,0,0,1);
}

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

.box {
   position: relative;
}
.box:before {
   content: “”;
   box-shadow: 1px 1px 1px rgb(0,0,0);
   opacity: .5;
   transition: .2s;
   position: absolute;
   width: 100%;
   height: 100%;
}
.box.active:before {
   opacity: 1;
}

Ручная оптимизация

Есть и хорошие новости: разработчики могут выбирать свойства, которыми они хотят управлять, создавать составной слой и перетаскивать элементы на этот слой. Убедиться, что элемент всегда отрисовывается вручную, это также самый простой способ уведомить браузер о том, что элемент готов к отрисовке. Сценарии, для которых требуется отдельный слой, включают в себя: состояние элемента будет претерпевать некоторые изменения (например, анимация), изменение стиля, требующего высокой производительности (например,position:fixedа такжеoverflow:scroll). Возможно, вы также сталкивались с низкой производительностью, вызывающей мерцание страниц, вибрацию... или другие нежелательные эффекты, такие как обычный мобильный заголовок, закрепленный в верхней части области просмотра, который мерцает при прокрутке страницы. Разделение таких элементов на их собственный составной слой является распространенным решением проблемы такого типа.

метод взлома

Раньше разработчики обычноbackface-visibility:hiddenилиtrasform: translate3d(0,0,0)Запускает браузер для создания нового составного слоя, но это не стандартно, и ни один из этих двух методов не влияет на визуальный эффект элемента.

новый метод

теперь естьwill-change, который может явно уведомить браузер о необходимости оптимизировать отрисовку одного или нескольких элементов элемента.will-changeПолучает различные значения свойств, например одно или несколько свойств CSS (transform, opacity),contentsилиscroll-position.不过最常用值可能就是auto

.box {
  will-change: auto;
}

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

метод анимации

Вы можете использовать CSS (декларативный) или JavaScript (императивный) для перемещения элементов, в зависимости от ваших потребностей.

Декларативная анимация

CSS 动画是声明式的(告诉浏览器要做什么),浏览器需要知道动画的起始状态和终止状态,这样它才知道如何优化。 CSS 动画不是在主线程中执行,不会妨碍主线程中的任务执行。 В основном,Анимации CSS более удобны для производительности. Комбинация анимаций ключевых кадров обеспечивает довольно богатые визуальные эффекты, такие как анимация бесконечного вращения элемента ниже:

@keyframes spin {
    from {transform: rotate(0deg);}
    to {transform: rotate(360deg);}
}
.box {
   animation-name: spin;
   animation-duration: 3ms;
   animation-iteration-count: infinite;
   animation-timing-function: linear;
}

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

const box = document.getElementById("box")
box.addEventListener("click", function(){
    box.classList.toggle("class-name");
});

Стоит отметить, что если вы работаете с «выпуском» (Примечание: определенная область, отведенная по четырем сторонам холста в дизайне, называется «выпуском»), новыйWeb Animation APIВоспользуется преимуществами производительности CSS. С помощью этого API разработчики могут легко справляться с проблемами синхронизации и синхронизации анимации с учетом производительности.

Команда анимация

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

requestAnimationFrame

requestAnimationFrameУдобно для производительности, вы можете видеть это какsetTimeout的进化版,不过这其实是一个动画执行的 API。理论上调用了这个 API 就能保证 60fps 的帧率,但实践证明这个函数是请求在下一次可用时绘制动画,也就是并没有固定的时间间隔。浏览器会把页面上发生的变化组合接着一次绘制,而不会为每一次变化都进行绘制,通过这个方式提升 Использование процессора. RAF 可以递归地使用:

function doSomething() {
    requestAnimationFrame(doSomething);
    // Do stuff
}
doSomething();

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

прокрутить

Плавная прокрутка достигает хорошей производительности, но вызов. К счастью, недавняя спецификация обеспечивает ряд настраиваемых вариантов. Разработчики больше не нуждаются в поведении по умолчанию, отключая браузер (preventDefault), ОткрытьPassive event listenersПрокрутите, чтобы улучшить производительность (после оператора, вам не нужно следить за проседателем событий прокрутки колеса мыши, чтобы оптимизировать производительность, предотвращая работу элемента сенсорного события). Использование только будет объявлено нуждающимся в слушателях{passive: true}:

element.addEventListener('touchmove', doSomething(), { passive: true });

Из Chrome 56 эта опция будетtouchmoveа такжеtouchstartВключен по умолчанию.

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

Читать перед записью

Постоянное чтение и запись в DOM может привести к «принудительной синхронной раскладке», но с течением времени технология превратилась в более образный термин — «прокрутка раскладки». Как упоминалось ранее, браузер будет отслеживать «грязные элементы» и при необходимости сохранять процесс преобразования. Разработчики могут заставить браузер выполнять предварительные вычисления после чтения определенных свойств. Такие повторяющиеся операции чтения и записи вызовут перестановки. К счастью, есть простое решение: читать и писать.

Чтобы смоделировать эффекты, описанные выше, рассмотрим следующий пример, предъявляющий строгие требования к читателю:

boxes.forEach(box => {
    box.style.transform = “translateY(“ + wrapper.getBoundingClientRect().height + “px)”;
})

«Читать» вforEachСнаружи вместо того, чтобы делать это каждую итерацию вместе с "записью", можно повысить производительность:

let wrapperHeight = wrapper.getBoundingClientRect().height + 'px';
boxes.forEach(box => {
    box.style.transform = “translateY(“ + wrapperHeight + “px)”;
})

Оптимизированное будущее

Браузеры продолжают вкладывать все больше и больше усилий в оптимизацию производительности. через новую недвижимостьcontainВы можете объявить, что поддерево элемента не зависит от других элементов страницы (в настоящее время только Chrome и Opera поддерживают это свойство). Это равносильно тому, чтобы сообщить браузеру: «Этот элемент безопасен, он не влияет на другие элементы».containЗначение атрибута определяется в соответствии с диапазоном изменения, который может бытьstrict,content,size,layout,styleилиpaint. Это гарантирует, что при обновлении поддерева не произойдет перегруппировка родительского элемента. Особенно при внедрении сторонних элементов управления:

.box {
   contain: style; // 限制样式范围在元素和它的子元素中
}

Тестирование производительности

Как только вы узнаете, как оптимизировать производительность страницы, вам нужно провести тестирование производительности. На мой взгляд, Chrome Developer Tools — лучший инструмент для тестирования. В «Дополнительных инструментах» есть панель «Визуализация», которая содержит такие параметры, как отслеживание «грязных элементов», расчет частоты кадров в секунду, выделение границ каждого слоя и отслеживание проблем с производительностью прокрутки.

'Rendering' 面板中的可选项

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

Еще одним интересным инструментом является «Дросселирование ЦП» в «Настройках Caputrue». Этот параметр позволяет разработчикам имитировать работу страницы на очень медленном устройстве. Разработчики вполне могут тестировать свои страницы в настольных браузерах, потому что ПК или Mac по своей природе лучше, чем мобильные устройства. Эта опция обеспечивает хорошую симуляцию реальной машины.

一条合格的 'Timeline'

тестировать и повторять

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

1