Анимации, Google RAIL, что делать?
Усі статті, обговорення, новини про Front-end — в одному місці. Підписуйтеся на телеграм-канал!
Люди преуспели в отслеживании движения, им не нравится, если анимация не плавная. Пользователи воспринимают анимацию плавной, когда обрабатывается 60 новых кадров в секунду. По 16 мс на кадр, включая время, которое требуется для браузера, чтобы нарисовать кадр на экране, 10мс для создания кадра вашим скриптом.
Анимация: создание кадра за 10мс
Анимация-это не просто необычные эффекты Ul. Например, прокрутки и касания — это типы анимации.
Пользователи замечают, когда в анимации частота кадров варьируется. Ваша цель — произвести 60 кадров в секунду, и каждый кадр должен пройти через все эти шаги:
Шаги, воспроизведения кадра
С чисто математической точки зрения, каждый кадр имеет бюджет около 16 мс (1000 мс / 60 кадров в секунду = 16.66 мс на кадр). Однако, потому что браузеру нужно немного времени, чтобы нарисовать новый кадр на экране, ваш код должен закончить выполнение за 10мс.
В точках высокой нагрузки, таких как в анимации, самое главное — это ничего не делать, когда это возможно, и делать по минимуму, когда невозможно. Когда это возможно, — использовать 100мс, предварительно просчитав объем работ так, чтобы был шанс попадания 60 кадров в секунду.
Дополнительные сведения см. в разделе «Отображение»
Цитата из Google RAIL, рекомендаций по скорости работы отзывчивых веб-приложений.
Предисловие
Анимации очень распространенный прием, с которым сталкиваются JavaScript-разработчики, Google не просто так включил их отдельным пунктом в RAIL, ведь именно анимации одни из самых прожорливых операций. Так как в своей самой распространенной JavaScript реализации меняют css-стили, многократно дергая DOM, что очень плохо сказывается на производительности такого скрипта.
Мы привыкли ко многому, но когда обращаешь на это внимание, дерганые анимации — это действительно раздражает.
Хорошо видна дерганность анимации на примерах jscrollpane, прокрутите скролл колесиком, тут FPS очень низок для того, чтобы сохранить производительность. А вот демки Custom Scrollbar — уже выглядит неплохо. Дерганье заметить практически невозможно, но тем не менее и у него есть возможность снизить частоту кадров, ведь даже самый быстрый скрипт станет медленным, если дергать его слишком часто. Кстати на нашем старом hp в офисе, кастом скроллбар уже заметно подергивается.
Решение Яндекса
Яндекс в свое время на хабре опубликовал статью с решением этой проблемы — они поступили очень хитро — используют обычный скролл, но поверх него лежит кастомный скролл. Кастомный скролл всегда плавный, но не обязательно соответствует реальному положению страницы, и скроллбар не всегда под мышкой если тянуть его вручную. Решение, соответствущее G. RAIL, приятно глазу, но часто подобное отставание анимации непростительно.
Что делать?
el.animate()
Забудьте, эта штука еще крайне не кроссбраузерна, «Safari no support» не то, с чем согласится заказчик, а полифилы дадут такой же animate, как в jQuery.
Решение на поверхности
Да, но увы на чистом JavaScript решения пока нет, ведь без нативных анимаций вы так или иначе вы будете обращаться к el.style очень часто, потому могу посоветовать комбинировать javascript и css, такое решение будет элегантным, не зря ведь опытные разработчики постоянно говорят новичкам — «не пишите html/css в скриптах», очень не зря. Давайте рассмотрим, как с этим работать.
Для начала, банально переключим класс
const updateTransition = function() { return new Promise( (res, rej) => { var el = document.querySelector(".parent div"); var isStatus = el.matches( '.box'); el.classList.toggle( "box1", isStatus); el.classList.toggle( "box", !isStatus) var cb = function(){ //once event el.removeEventListener("transitionend",cb, false); res(); el.addEventListener("transitionend", cb, false); }); } var btn = document.querySelector("#btn"); btn.addEventListener("click", () => { updateTransition().then( () => { console.log( `end ${Date.now()}`); }); });
Wow! много буков? давайте проще, в основе тут вот эти строки
//Находим элемент var el = document.querySelector(".parent div"); //проверяем статус анимации var isStatus = el.matches( '.box') //ставим нужные классы анимации el.classList.toggle( "box1", isStatus); el.classList.toggle( "box", !isStatus);
Остальное просто обвязка для асинхронной работы и запуску по клику.
Можно было обойтись одним классом, два поскольку этот код писали наши студенты на практическом занятии, я старался не менять его для небольшой саморекламы конечно.
Что если заранее не известно есть ли анимация?
проверьте наличие свойства transition и animate после назначения класса.
А если отменят анимацию?
На самом деле это можно отследить только отслеживая изменения свойств, по крайней мере мне не известен иной способ. События transitioncancel увы нет, но намного чаще нужна функция просто остановки анимации, в том же jQuery это .stop(), однако при смене класса анимации, текущая анимация, автоматически остановиться и начнеться новая.
Цепочки анимаций?
Легко сделать используя цепочки промисов
var chain = Promise.resolve(); for( условие цикла ){ chain = chain.then( ()=> { //код который надо чейнить }) }
Не привожу выше полный пример, ибо сейчас когда дописываю эту статью, у меня уже четыре часа утра, но с радостью покажу вам применение чейнов отвечая на ваши коментарии когда проснусь.
На последок, Много кода?
На самом деле только только el.classList.toggle( className), остальное — логика которая так или иначе у вас будет присутствовать в приложении.
Послесловие с благодарностью нашим студентам
В любом коде возникают проблемы, однако тормозящая анимация это то что видят все посетители сайта, это действительно проблема, если вы только не пишите код ради кода, мы должны заботиться о тех кто в итоге будет пользоваться нашим продуктом.
Использовать классы в целом удобно, например у вас есть переключение мобильного и обычного меню, все что вам нужно, это назначить другой класс, любые настройки анимаций остаются за пределами кода, логика становиться более прозрачной и проще читается. Это будет сложно для тех кто не привык активно использовать обещания или мало работал эвентами, ну что ж, это хороший тогда повод прокачать свой скил, удачи котаны!
Код в статье взят из домашек студентов ProCode.com.ua, Николая Кравченко и Максима Бурды, промисы детально рассматриваются у нас на курсе «JS Frontend», цепочка анимаций на промисах один из стандартных применений этого паттерна.
12 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів