Анимация — несколько рисунков, показанных последовательно, чтобы создать иллюзию движения. Анимации привлекают внимание пользователей и помогают сделать интерфейсы понятными. Мы подготовили перевод статьи, чтобы разобраться, как контролировать движения и переходы в CSS.
Есть два способа анимировать элементы в CSS: свойства animationи transition.
Свойство animationпозволяет изменять свойства элемента в течение определённого периода, а transitionопределяет, как элемент меняется за определённый период.
Возникает вопрос, в чём же разница. Для animation нужны @keyframes, то есть требуется определить точки начала и конца изменений. Ключевые кадры используют для пошаговых анимаций. Более простые анимации создают при помощи transition. В этом случае движение запускается по определённому сигналу, например, по клику или наведению курсора. Свойства animation и transition управляют продолжительностью, задержкой, итерациями движения.
Что такое временные функции
Это функции, которые определяют, как веб-элементы работают в каждом кадре анимации: animation-timing-function и transition-timing-function действуют и как автономные свойства CSS, и как значения свойств animation и transition .
Поэтому свойство animation может выглядеть так:
animation: <name> <duration> <timing-function>;Или так:
animation-name: name;
animation-duration: 500ms;
animation-timing-function: ease;То же самое со свойством transition:  
transition: <property> <duration> <timing-function>;Или:
transition-property: transform;
transition-duration: 500ms;
transition-timing-function: ease;Transition-timing-function
Transition-timing-function определяет кривую скорости эффекта перехода. Кривая — соединение множества точек. Так что каждый период transition разделён на несколько точек.
Всего в CSS шесть transition-timing-functions:
- linear
- ease
- ease-in
- ease-out
- ease-in-out
- cubic-bezier()
Они служат для создания плавных переходов, поэтому называются функциями плавности.
Функция linear
Анимации с linear двигаются с постоянной скоростью. При этом с начала до конца никаких изменений внутри функции нет, так что кривая скорости тут, скорее, прямая.

Функция ease
Анимации с этой функцией начинаются медленно, ускоряются, потом снова замедляются до стартовых значений. Эта функция используется по умолчанию.

Для понимания устроим гонки, участвуют ease и linear:

Используем простую разметку HTML:
<body>
  <div class="container">
    <div class="rockets rocket-1"><img src="Rocket1.png"></div>
    <div class="rockets rocket-2"><img src="Rocket2.png"></div>
  </div>
</body>Добавляем CSS:
body {
  margin: 0px;
  padding: 0px;
}
*{
  box-sizing: border-box;
}
.container{
  width: 100%;
  height: 300px;
  background: rgba(224,214,233, 0.5)
}
.rockets{
  width: 500px;
  height: 100px;
  transition-duration: 2s;
  transition-property: transform;
  display: flex;
  align-items: center;
}
.rockets img{
  height: 100px;
  border-right: 1px solid red;/*To track the speed easily*/
}Добавляем анимацию. Триггером делаем :hover. 
.container:hover .rockets{
  transform: translateX(500px);
}
.rocket-1{
  transition-timing-function: linear;
}
.rocket-2{
  transition-timing-function: ease;
}Итог:

На первый взгляд, кажется, что ease быстрее, чем linear, но в обоих случаях animation-duration одинаково. Если присмотреться, обе анимации заканчиваются в одной точке. В гонке ничья.
Функции ease-in, ease-out и ease-in-out
Анимации с функцией ease-in начинаются медленно, ускоряются к концу. Функция ease-out вызывает обратный эффект: быстрый старт и медленный финал.

Ease-in-out анимания начинается медленно, ускоряется в середине, завершается медленно. Похоже на ease, но только с симметричной кривой скорости. 

Снова гоночки:

.rocket-1{
  transition-timing-function: ease-in;
}
.rocket-2{
  transition-timing-function: ease-out;
}
.rocket-3{
  transition-timing-function: ease-in-out
}
Функция cubic-bezier()
Все функции плавности основаны на кубической кривой Безье, которая определяется контрольными точками. Даже linear  — кривая Безье с двумя контрольными точками.
cubic-bezier(P1,P2,P3,P4)Точки P1 и P3 должны быть в пределах от 0 до 1. Точки P2 и P4 могут быть с любыми значениями, в том числе отрицательными. Удобнее создавать все точки в пределах от -1 до 1, чтобы анимации не дёргались.
Зададим рандомные значения для точек.
.rocket-1{
  transition-timing-function: cubic-bezier(.66,.39,.21,.67);
}
.rocket-2{
  transition-timing-function: cubic-bezier(1,-0.42,.42,-0.39);
}
.rocket-3{
  transition-timing-function: cubic-bezier(.57,1.34,.21,0);
}Наводим курсор и смотрим, что вышло.

Значения для контрольных точек можно задавать вручную, но это довольно долго. Есть два способа выбрать идеальную скорость cubic-bezier(): инструменты разработчика и генератор. 
Используем инструменты проверки
Задаём анимированному элементу любую временную функцию. Открываем инструменты разработчика. У нас скриншоты из Chrome.
Если вы используете сокращённые свойства animation или transition, рядом с названием свойства найдёте значок раскрывающегося списка. Кликаем, раскрываем список значений — среди них будет время. В другом случае это свойство отображается отдельно. 

Рядом с названием временно функции есть значок кривой, который открывает редактор Безье.

Кликаем и регулируем cubic-bezier(). В этом помогает визуализатор.

Когда найдёте подходящую кривую скорости, скопируйте cubic-bezier() и вставьте в проект.

Используем генератор
Заходим на cubic-bezier.com — это инструмент, которые создаёт кривые скорости. Поиграйте с настройками, пока не найдёте подходящий вариант. В это помогут предварительный просмотр и сравнение с функциями по умолчанию. Скопируйте и вставьте в проект.

Animation-timing-function
Функция animation-timing-function определяет кривую скорости. Да, тоже. Свойство  animation делится на @keyframes, которые работают как FPS у камер. Animation-timing-function работает с любой функцией плавности, а также с другими функциями: step-end, step-start и steps.
Когда со свойством animation используют функция плавности, нужно добавлять  @keyframes с начальной и конечной точками. Посмотрим, как это работает. Сделаем анимации скролла, элементы будут появляться при прокрутке вниз. 

Начинаем:
<section class="container">
     <h2>Ease-in, Ease-out, and Ease-in-out</h2>
        <div class="text-container">
          <div class="text-box reveal box-3">
            <h3>Ease-in</h3>
            <p>Random text</p>
          </div>
          <div class="text-box reveal box-4">
            <h3>Ease-out</h3>
            <p>Random text</p>
          </div>
          <div class="text-box reveal box-5">
            <h3>Ease-in-out</h3>
            <p>Random text</p>
          </div>
        </div>
</section>Стилизуем и присваиваем каждому элементу animation:  
.active.box-1 {
  animation: box-1 1s ease;
}
.active.box-2 {
  animation: box-2 1s linear;
}
.active.box-3 {
  animation: box-3 1s ease-in;
}
.active.box-4 {
  animation: box-4 1s ease-out;
}
.active.box-5 {
  animation: box-5 1s ease-in-out;
}
.active.box-6 {
  animation: box-6 1s cubic-bezier(.66,.39,.21,.67);
}
.active.box-7 {
  animation: box-7 1s cubic-bezier(1,-0.42,.42,-0.39);
}
.active.box-8 {
  animation: box-8 1s cubic-bezier(.57,1.34,.21,0);
}Все анимированные элементы сопровождаем классом reveal, который спрячет их до запуска анимации.  
.reveal {
  position: relative;
  opacity: 0;
}
.reveal.active {
  opacity: 1;
}Анимации прокрутки контролируем функцией JavaScript:
 function reveal() {
        var reveals = document.querySelectorAll(".reveal");
        for (var i = 0; i < reveals.length; i++) {
          var windowHeight = window.innerHeight;
          var elementTop = reveals[i].getBoundingClientRect().top;
          var elementVisible = 150;
          if (elementTop < windowHeight - elementVisible) {
            reveals[i].classList.add("active");
          } else {
            reveals[i].classList.remove("active");
          }
        }
      }
      window.addEventListener("scroll", reveal);Условие запуска анимации — появление элемента при скролле страницы. Эта функция отслеживает дистанцию прокрутки элемента, elementTop, пока скролл не достигнет точки, в которой элемент должен быть видимым, elementVisible.
getBoundingClientRect().top — расстояние от верхней точки области просмотра, window.innerHeight — высота области просмотра.
Далее@keyframes:
@keyframes box-1 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
@keyframes box-2 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
@keyframes box-3 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
@keyframes box-4 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
@keyframes box-5 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
@keyframes box-6 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
@keyframes box-7 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
@keyframes box-8 {
  0% {
    transform: translateY(100px);
    opacity: 0;
  }
  100% {
    transform: translateY(0);
    opacity: 1;
  }
}
Функции step-end, step-start и steps()
Эти функции разбивают анимацию на равные части или шаги: step-end запускает анимацию после первого @keyframe и пропускает шаг в конце, step-start действует наоборот. Вот как это работает:
.rockets{
  width: 500px;
  height: 100px;
  animation-duration: 2s;
  animation-name: flight;
  animation-iteration-count: infinite;
  animation-direction: alternate-reverse;
  display: flex;
  align-items: center;
}
.rocket-1{
  animation-timing-function: step-end;
}
.rocket-2{
  animation-timing-function: step-start;
}
@keyframes flight{
  0%{transform: none;}
  25%{transform: translateX(125px);}
  50%{transform: translateX(250px);}
  75%{transform: translateX(375px);}
  100%{transform: translateX(500px);}
}Итог:

Ракета с step-start переходит к первому @keyframe, как только начинается анимация. 
Для усложнения используем steps(), чтобы указать количество шагов в анимации:
.rocket-1{
  animation-timing-function: steps(5);
}
.rocket-2{
  animation-timing-function: steps(10);
}
.rocket-3{
  animation-timing-function: steps(20);
}
@keyframes flight{
  0%{transform: none;}
  100%{transform: translateX(500px);}
}Итог:

Ключевые слова, которые можно использовать со steps() в дополнение к количеству шагов:
- jump-start
- jump-end
- jump-both
- jump-none
Jump-start и jump-end работают так же, как step-start и step-end; jump-both — анимация пропускает шаг с обоих концов; jump-none— анимация не пропускает ни одного шага, каждый шаг равномерно распределён по продолжительности.
.rocket-1{
  animation-timing-function: steps(5,jump-end);
}
.rocket-2{
  animation-timing-function: steps(5,jump-start);
}
.rocket-3{
  animation-timing-function: steps(5,jump-both);
}
.rocket-4{
  animation-timing-function: steps(5,jump-none);
}
@keyframes flight{
  0%{transform: none;}
  100%{transform: translateX(500px);}
}Результат:

Глобальные временные функции
Работают для всех свойств CSS, в том числе:
- inherit: даёт дочернему элементу наследуемые свойства родительского. Если свойства не наследуются, то возвращаются к- initial.
- initial: кажется, что- initial— способ использовать дефолтные значения свойств, но это не всегда так. У временных функций- initialсовпадает с дефолтным значением ease.
- revert: устанавливает свойства элемента как дефолтные CSS свойства браузера.
- unset: похоже на- revert, но с дополнениями. Влияет на наследуемые и ненаследуемые свойства.
Свойства выше — наследуемые. К сожалению, animation-timing-function и transition-timing-function не наследуются.
Итак, если свойство наследуется, unset присваивает ему значение inherit. Если нет — свойству присваивается значение initial.
Бонус: animation-delay и transition-delay
Свойство -delay можно использовать с временными функциями: animation-delay и transition-delay откладывают старт анимации. Добавить свойство можно при помощи сокращения:
animation: <name> <duration> <timing-function> <delay>;
transition: <property> <duration> <timing-function> <delay>;Порядок свойств неважен, вторым значением времени в объявлении всегда будет свойство delay. Если у нас такое объявление:  
transition: transform 2s 1s ease;Тогда transition-delay равняется 1s. Это же относится animation.
Покажем на примере:
.rocket-1{
   transition-timing-function: cubic-bezier(.66,.39,.21,.67);
   transition-delay: 500ms;
}
.rocket-2{
   transition-timing-function: cubic-bezier(.66,.39,.21,.67);
   transition-delay: 700ms;
}
.rocket-3{
  transition-timing-function: cubic-bezier(.66,.39,.21,.67);
  transition-delay: 1s;
}
Такое свойство можно использовать для загрузки разных разделов веб-страницы без необходимости определять разные animation или transition для каждого раздела.
 
          