# Обзор возможностей

Vue предоставляет некоторые абстракции, которые могут помочь в работе с переходами и анимациями, особенно в ответ на изменения чего-либо. Некоторые из них включают в себя:

  • Хуки для компонентов, добавляемых или удаляемых из DOM, как для CSS, так и для JS, с помощью встроенного компонента <transition>.
  • Режимы перехода для возможности оркестрации порядка выполнения во время перехода.
  • Хуки для списка элементов, положение которых на странице изменяется, с поддержкой техники FLIP под капотом для увеличения производительности, с помощью компонента <transition-group>.
  • Переходы между различными состояниями в приложении с помощью watchers.

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

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

# Анимации и переходы на классах

Несмотря на то, что компонент <transition> замечательно подходит для анимации появления и исчезновения компонентов, анимацию также можно активировать без монтирования компонента, просто добавляя определённый класс по условию.

<div id="demo">
  Push this button to do something you shouldn't be doing:<br />

  <div :class="{ shake: noActivated }">
    <button @click="noActivated = true">Click me</button>
    <span v-if="noActivated">Oh no!</span>
  </div>
</div>
1
2
3
4
5
6
7
8
.shake {
  animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
  transform: translate3d(0, 0, 0);
  backface-visibility: hidden;
  perspective: 1000px;
}

@keyframes shake {
  10%,
  90% {
    transform: translate3d(-1px, 0, 0);
  }

  20%,
  80% {
    transform: translate3d(2px, 0, 0);
  }

  30%,
  50%,
  70% {
    transform: translate3d(-4px, 0, 0);
  }

  40%,
  60% {
    transform: translate3d(4px, 0, 0);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const Demo = {
  data() {
    return {
      noActivated: false
    }
  }
}

Vue.createApp(Demo).mount('#demo')
1
2
3
4
5
6
7
8
9

See the Pen Create animation with a class by Vue (@Vue) on CodePen.

# Переходы с привязками к стилям

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

<div id="demo">
  <div
    @mousemove="xCoordinate"
    :style="{ backgroundColor: `hsl(${x}, 80%, 50%)` }"
    class="movearea"
  >
    <h3>Move your mouse across the screen...</h3>
    <p>x: {{x}}</p>
  </div>
</div>
1
2
3
4
5
6
7
8
9
10
.movearea {
  transition: 0.2s background-color ease;
}
1
2
3
const Demo = {
  data() {
    return {
      x: 0
    }
  },
  methods: {
    xCoordinate(e) {
      this.x = e.clientX
    }
  }
}

Vue.createApp(Demo).mount('#demo')
1
2
3
4
5
6
7
8
9
10
11
12
13
14

See the Pen Интерполяция с помощью привязок стилей by Vue (@Vue) on CodePen.

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

# Производительность

Можно заметить, что в примерах анимации выше используются такие вещи как transform и применяются странные свойства, например perspective — зачем они нужны, и почему построены таким образом вместо простого использования свойств margin и top и т.п.?

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

# Трансформации и прозрачность

Можно обратиться к специальным ресурсам, таким как CSS-Triggers (opens new window), чтобы узнать какие свойства будут приводить к перерисовке страницы (repaint), если будем их анимировать. Если посмотреть что указано под transform, можно увидеть следующее:

Применение трансформаций не вызывает никаких изменений геометрии или отрисовки, что очень хорошо. Это означает, что операция скорее всего может быть выполнена в compositor thread с поддержкой GPU.

Свойство opacity ведёт себя аналогичным образом. Поэтому, они являются идеальными кандидатами для создания анимаций перемещений.

# Аппаратное ускорение

Свойства perspective, backface-visibility и transform: translateZ(x) подсказывают браузеру, когда требуется использовать аппаратное ускорение.

Если нужно аппаратное ускорение для элемента, можно применить любое из этих свойств (не все сразу, только одно):

perspective: 1000px;
backface-visibility: hidden;
transform: translateZ(0);
1
2
3

Многие JS-библиотеки, такие как GreenSock, считают что аппаратное ускорение нужно всегда и будут применять его по умолчанию, так что включать вручную не потребуется.

# Тайминги

Простые переходы в интерфейсе чаще всего просто переход из одного состояния в другое без каких-либо промежуточных состояний, а тайминг в таких случаях обычно между 0.1s и 0.4s, в большинстве случаев 0.25s. Можно ли указывать этот тайминг для всего? Нет, не совсем. Если есть что-то, чему нужно двигаться на большее расстояние или требуется больше шагов или смен состояний, то 0.25s далеко не всегда смотрится также хорошо, поэтому нужно будет более детально определить уникальные тайминги. Но это не значит, что больше не будет хороших настроек по умолчанию, которые можно переиспользовать в приложении.

Также можно заметить, что появления лучше выглядят с чуть большей длительностью, чем исчезновения. Пользователь, как правило, направляется на этапе появления, но немного нетерпелив на этапе исчезновения, потому что желает идти своим путём дальше.

# Функции плавности

Функция плавности (easing) — является важным способом передачи глубины анимации. Наиболее распространённая ошибка новичков — использовать ease-in для появления/входа и ease-out для исчезновения/выхода. На самом деле, всё надо сделать наоборот.

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

.button {
  background: #1b8f5a;
  /* применяется к начальному состоянию, поэтому */
  /* этот переход будет виден при возвращении к этому состоянию */
  transition: background 0.25s ease-in;
}

.button:hover {
  background: #3eaf7c;
  /* применяется к состоянию при наведении, поэтому */
  /* этот переход будет применяться при срабатывании hover */
  transition: background 0.35s ease-out;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

See the Pen Пример функций плавности для перехода by Vue (@Vue) on CodePen.

С помощью функции плавности анимации также можно передать свойства материала. Возьмём песочницу с примером, какой из шариков кажется твёрдым, а какой мягким?

See the Pen Демо с подпрыгивающим шариком by Sarah Drasner (@sdras) on CodePen.

Можно получить множество уникальных эффектов и сделать анимацию очень стильной, регулируя функцию плавности. CSS позволяет управлять ею с помощью свойства cubic-bezier, а эта песочница (opens new window), которую сделала Lea Verou, будет очень полезна для изучения.

Хотя можно достичь огромных успехов в простых анимациях, управляя двумя точками функций плавности cubic-bezier, JavaScript предоставляет несравненно больше точек для возможности управления, а значит, и большую вариативность в результате.

Сравнение функций плавности

Возьмём для примера анимацию прыжка. В CSS нужно объявить каждый кадр (keyframe), верх и низ. В JavaScript, можно выразить все перемещения с помощью готовой функции анимации, передав bounce в GreenSock API (GSAP) (opens new window) (в других JS-библиотеках есть свои варианты анимаций по умолчанию).

CSS-код для прыжка (пример из animate.css):

@keyframes bounceInDown {
  from,
  60%,
  75%,
  90%,
  to {
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
  }

  0% {
    opacity: 0;
    transform: translate3d(0, -3000px, 0) scaleY(3);
  }

  60% {
    opacity: 1;
    transform: translate3d(0, 25px, 0) scaleY(0.9);
  }

  75% {
    transform: translate3d(0, -10px, 0) scaleY(0.95);
  }

  90% {
    transform: translate3d(0, 5px, 0) scaleY(0.985);
  }

  to {
    transform: translate3d(0, 0, 0);
  }
}

.bounceInDown {
  animation-name: bounceInDown;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

И его аналог в JS с использованием GreenSock:

gsap.from(element, { duration: 1, ease: 'bounce.out', y: -500 })
1

В некоторых примерах следующих разделов будет использоваться GreenSock. Также есть замечательный визуализатор анимаций (opens new window), который поможет создать прекрасные функции для анимации.

# Дальнейшее изучение

Deployed on Netlify.
Последнее обновление: 2021-01-07, 11:25:25 UTC