logo
Ещё

Как создать анимацию в JS

Анимация – это стильно, модно и молодежно. Как минимум она привлекает к себе внимание (ввиду устройства мозга человека), как максимум она может быть наглядной иллюстрацией к какому-либо процессу или «проводником» по функционалу сайта. Есть множество способов создания анимации: подход JavaScript Canvas, специализированные программы, атрибуты SVG, JS + CSS. Именно о последнем мы и будем говорить – одно свойство CSS может создать движение какого-либо объекта на странице, а подключенный к этому делу JS позволяет создавать сложные анимации с различными переходами.

Если вы только учитесь управляться с JavaScript, то для создания анимаций и довольно сложных эффектов вам с лихвой хватит двух языков: JS и CSS, и никакие дополнительные инструменты вам не нужны.

Анимация на сайтах

Зачем она нужна

Человек быстрее обращает внимание на движущиеся объекты, чем на статические – так наши древние предки имели больше шансов заметить съедобное и/или опасное животное и выжить. Вряд ли пещерные люди могли предположить, что в далеком будущем фронтенд-разработчики будут использовать эту особенность для привлечения внимания читателей – но случилось именно так. Анимация используется для того, чтобы сайт выглядел более живым – движение придают каким-либо ключевым объектам, которые пользователь должен заметить в первую очередь. Это могут быть формы регистрации, обратный звонок и так далее.

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

Ну и последняя цель – это внешняя красота. Скорее всего вы не будете спорить с тем, что плавно выезжающее меню выглядит более стильно, чем мгновенно вываливающийся кирпич. Но вот здесь есть определенная проблема – анимация «ест» довольно много ресурсов компьютера, и если вы будете прикручивать ее ко всему подряд – ваша страница будет грузиться и работать очень медленно.

Поэтому выдерживайте баланс между красотой и производительностью.

Как работает

Любому объекту можно прописать CSS свойство transform, которое, как понятно из названия, трансформирует какой-либо объект. Трансформации могут быть самыми разными – увеличение/уменьшение прозрачности, изменение размера, поворот, переход цвета и так далее. Но transform происходит очень быстро, поэтому только с его помощью сделать анимацию не получится. Но есть еще одно полезное свойство: transition, которое инициирует переход из одного состояния в другое с помощью transform и временного интервала, указанного в миллисекундах.

У такой анимации есть одна проблема – ее проблематично запустить несколько раз. Еще сложнее дела обстоят, если нам нужно запустить анимацию по триггеру или контролировать состояние завершения анимации. Здесь переходы CSS уже не помогут, поэтому нужно более действенное оружие: язык программирования JavaScript. JS пользуется в своей работе DOM-моделью, которая позволяет получить доступ как к каждому элементу, так и к каждому его свойству. Поэтому вы можете самостоятельно расставить позиции ключевых кадров (между которыми осуществляются переходы) и сделать так, чтобы анимация запускалась или отключалась тогда, когда вам это нужно – при загрузке страницы, по клику на элементе, после определенного временного интервала и так далее. Кроме того, в CSS есть свойство плавных переходов, которое позволяет тонко настроить скорость воспроизведения анимации.

Необходимые инструменты для работы

Использование setInterval

setInterval – это базовая функция для анимации. Она позволяет устанавливать интервал, с которым происходит то или иное действие. Естественно, в анимации, буквально построенной на интервалах, используется функция очень часто. Синтаксис:

setInterval(function() {…}, 50};

Внутрь мы передаем 2 аргумента – функцию, которую мы будем выполнять, и время повторения, то есть функция исполнится за указанное (в миллисекундах) время. Как это работает:

timer = setInterval(function() {

var now = +new Date,

deltaT = now - lastFrame;

elem.style.left = ( left += 10 * deltaT / 16 ) + "px";

lastFrame = now;

if ( left > 400 ) {

clearInterval( timer );

}

}, 16);

Здесь мы каждые 16 миллисекунд запускаем функцию, которая отслеживает прошедшее время через объект Date и смещает позицию элемента влево на 1 пиксель каждый фрейм.

Если оказывается, что объект уехал более чем на 400 пикселей влево, мы все сбрасываем.

Использование requestAnimationFrame

В предыдущем коде есть одна сложность, которую новички обычно не учитывают. Когда браузер анимирует элемент предыдущим способом, он вообще не учитывает загрузку процессора, у него есть задача – и он ее выполняет. Это приводит к тому, что если мы создадим сложную анимацию, она может съесть все выданные браузеру ресурсы и запросить новые, даже в том случае, если вкладка не активна. Выполнить анимацию более эффективно можно с помощью нового метода, requestAnimationFrame. Функция requestAnimationFrame исполняется на усмотрение браузера – то есть он анализирует свои ресурсы и свою загруженность, и если браузер считает, что сейчас целесообразно запустить процесс – анимация начинается. Это позволяет анимировать страницу без существенной нагрузки на процессор. Если вы уже используете предыдущий код, вам лучше с помощью JavaScript переписать его вот так:

function animLoop( render, element ) {

var running, lastFrame = +new Date;

function loop( now ) {

if ( running !== false ) {

requestAnimationFrame( loop, element );

running = render( now - lastFrame );

lastFrame = now;

}

}

loop( lastFrame );

}

animLoop(function( deltaT ) {

elem.style.left = ( left += 10 * deltaT / 16 ) + "px";

if ( left > 400 ) {

return false;

}

}, animWrapper );

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

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

Position

Это уже относится к CSS. Когда вы создаете анимацию, вам обычно нужно отслеживать, где она находится, и при достижении какого-либо края (или другого условия) анимация должна каким-то образом менять свое поведение. Для того, чтобы точно знать позицию вашей анимации, вам нужно создать 2 div-блока, один внутри другого, и дать им разные имена, например – container и anima. У container нужно указать position: relative, и задать конкретную ширину и длину, что позволит адаптивно верстать этот контейнер. У anima нужно указать position: absolute, и тогда ваша анимация будет перемещаться строго внутри длины и ширины, заданных вышестоящим контейнером.

Плавность и кривые Безье

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

  • Linear. Переход осуществляется с одинаковой скоростью.
  • Ease-in. Переход начинается медленно, потом разгоняется до обычной скорости.
  • Ease-out. Переход начинается с нормальной скоростью, к концу замедляется.
  • Ease-in-out. Переход медленно начинается и медленно завершается, в остальное время он происходит с обычной скоростью.

Но есть еще более сложный способ задания плавности перехода – способ, который позволяет вам полностью контролировать скорость. Он основан на кривых Безье – математической функции для описания параметрической кривой. Суть – в том, что вы задаете координаты точек от 0, 0 до 1, 1, и по этим точкам строятся наиболее оптимальные для данных входных параметров кривые.


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

На практике же кривые Безье можно задавать прямо в CSS:

transition: transform 300ms cubic-bezier(0.351, 0.232, 0.732, 0.885);

Создаем анимацию

Виджер аккордеон

Самый простой жизненный пример анимации – это выпадающее меню. HTML выглядит так:

<button class="menu">Menu 1</button>

<div class="hidden_content">

<p>Some text</p>

</div>

<button class="menu">Menu 2</button>

<div class="hidden_content">

<p>Some text</p>

</div>

<button class="menu">Menu 3</button>

<div class="hidden_content">

<p>Some text</p>

</div>

Здесь мы создали 3 кнопки, каждой задали класс, под каждую кнопку мы поместили по блоку div с содержимым меню. Теперь нужно немного поколдовать с CSS:

/* Здесь мы задаем параметры кнопки, при нажатии на которую будет «вываливаться» содержимое */

.menu {

background-color: #ddd;

color: #222;

cursor: pointer;

padding: 14px;

width: 100%;

border: none;

outline: none;

transition: 1s;

}

/* Тут мы меняем цвет в двух случаях: если на кнопку навели курсор или если кнопка нажата. Класс active добавим через JS*/

.active, .accordion:hover {

background-color: #aaa;

}

/* Наконец, здесь нам нужно указать, как будет выглядеть сама панель под кнопкой. Изначально панель должна быть скрыта, поэтому display: none */

.hidden_content {

padding: 0 12px;

background-color: green

display: none;

overflow: hidden;

}

Наконец, все это нужно оживить силами JS:

var any_menu = document.getElementsByClassName("menu");

var n;

for (n = 0; n < any_menu.length; n++) {

any_menu[n].addEventListener("click", function() {

/* Нашли все кнопки по имени класса, засунули их в массив, на каждую кнопку повесили обработчик событий, вешающий класс active при нажатии */

this.classList.toggle("active");

/* Переворачиваем display, чтобы отображать, если до нажатия было скрыто, или скрыть, если до нажатия было отображено */

var content = this.nextElementSibling;

if (content.style.display === "block") {

content.style.display = "none";

} else {

content.style.display = "block";

}

});

}

CSS3 анимация

В CSS3 «завезли» новый функционал, и теперь анимацию можно делать исключительно с помощью CSS, без JS. Естественно, эта анимация будет проще, чем приведенная в примере выше, но она идеально подходит для маленьких анимированных вставок. В основе этой анимации лежат keyframes. Keyframes – это набор правил, который задает переход объекта из одного состояния в другое. Записываются они так:

@keyframes first_keyframe {

from {background-color: blue;}

to {background-color: green;}

}

Естественно, нам нужен объект, к которому это правило будет применяться:

div {

width: 50px;

height: 50px;

background-color: blue;

animation-name: first_keyframe;

animation-duration: 2s;

}

Здесь все понятно из названия – само правило меняет цвет фона, в name указывается имя правила, в duration указывается длительность анимации. Keyframes поддерживают довольно много опций:

  • Delay – задержка перед началом проигрывания;
  • Iteration count – сколько раз должно воспроизводиться (можно поставить бесконечное число раз);
  • Direction – задать направление или настроить альтернативный цикл;
  • Timing function – описывали выше, позволяет задавать плавность;
  • Fill mode – переопределяет стиль объекта в разных состояниях (до воспроизведения и после).
Подробности и примеры смотрите в документации в следующем разделе.

Что почитать по теме

Анимация – тема глубокая и сложная, поэтому мы настоятельно рекомендуем вам почитать документацию/спецификацию и прости простые интерактивные курсы:

Подведем итоги

Тезисно:

  • Анимация используется в самых разных ситуациях: для привлечения внимания, для создания интерактивности, для красоты и так далее.
  • Обычно анимация построена на JS и CSS. CSS задает оформление всех элементов и описывает переходы, а JS управляет этими переходами и при необходимости назначает элементам классы/убирает классы, описанные в CSS.
  • Анимация – сложная тема, поэтому мы советуем вам сначала пройти ряд курсов, а затем долго и упорно практиковаться.
  • С выходом CSS3 появилась возможность создавать анимацию без использования JS – эта анимация будет более скудной на эффекты, но создать ее будет гораздо легче. Еще один плюс такой анимации – она практически ничего не весит и не загружает процессор, анимация на JavaScript таким похвастаться не может.
Часто ищут