Анимации в библиотеке компонентов: виды анимаций, UX/UI паттерны, подходы в Angular с dependency injection

Kate

Administrator
Команда форума
Хороший интерактивный дизайн формирует позитивный пользовательский опыт. Многие компании, которые создают библиотеки компонентов, помимо всего, пишут документацию с разделами по анимации и даже поставляют готовые пакеты помогающие строить переходы и передвижения согласно их спецификации.

В этой статье мы рассмотрим виды анимаций в веб приложениях. Паттерны UX/UI анимаций в дизайн системах и их реализацию на Angular. Также, будет показан способ организации анимаций в библиотеках с учетом переиспользования и кастомизации.

0b55ad6662018f1e7a9b2c800a6971c8.gif

В предыдущих статьях я писал, что мы документируем в наших библиотеках:

  • типографику
  • палитру
  • иконки
  • сетку
  • Angular составляющие (компоненты, директивы, пайпы, сервисы)
Недавно мы решили добавить новый раздел - Анимация. Давайте рассмотрим его.

Цели и принципы интерактивного дизайна​

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

  • Дизайн ориентированный на цели - техника, которая помогает пользователю достигать цели в приложении.
  • Удобство использования - функционал должен быть интуитивно понятным и надежным, тогда пользователь сможет получить удовольствие от работы. Да, это верно и для анимаций.
  • Отображение функционала - элемент интерфейса должен демонстрировать свое предназначение.
  • Обучаемость - интерфейсы, которые похожи своим поведением на остальные более предсказуемы и с ними проще разобраться за счет предыдущего опыта пользователя. Поэтому анимации тоже следует документировать и делать переиспользуемыми.
  • Обратная связь и время отклика - интерфейсы и компоненты должны мгновенно реагировать на действия пользователя. Сюда относится и "видимая производительность". Длительные операции всегда можно скрыть анимацией.

Виды анимаций в браузере​

После рассмотрения целей, перейдем к способам создания анимаций. Не будем подробно останавливаться на каждом, но зафиксируем способы их оптимизации. Существует две технологии анимации:

css анимация - позволяет анимировать переходы от одной конфигурации CSS стилей к другой.

Для оптимизации css анимаций нужно знать, что существует свойство will-change, которое подскажет браузеру об изменении элемента. Это повысит отзывчивость интерфейса. Про свойство можно подробней почитать в статье по ссылке.
javascript анимация - создавать более сложные анимации в отличие от css.

Для оптимизации javascript анимации нужно использовать requestAnimationFrame - указывает браузеру на то, что вы хотите произвести анимацию, и просит его запланировать перерисовку на следующем кадре анимации. Читаем подробности по ссылке.

Анимация Angular​

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

  • Работают поверх javascript анимаций
  • Поставляются из коробки с Angular
  • Удобное API для работы с состоянием компонента. Можно вызывать анимацию на dom элемент, на переменную в шаблоне. Создавать цепочку анимаций.
  • Есть средства для переиспользования анимаций

Создадим несколько UI/UX паттернов анимации​

Паттерн: объяснение происходящего (What Just Happened), добавление элемента. Допустим у нас происходит какое-либо действие в результате которого добавляется новый элемент в список или таблицу. Визуально элемент может быть очень похожим по своим данным и пользователь может не заметить, что новый элемент появился на форме. Это нарушает принципы интерактивного дизайна. Реализуем эту разновидность паттерна с добавлением элемента.

Посмотрим сразу на результат:

Добавление элемента Angular animation
Добавление элемента Angular animation
Исходный код шаблона:

<div class="table">
<div
*ngFor='let item of items; index as i; trackBy:id'
@fadeExplainMotion
[@.disabled]="isIniting"
>
....
</div>
</div>
Исходный код анимации в компоненте :

animations: [trigger('fadeExplainMotion', [
transition(
':enter',
animation([
style({
transform: 'translate(25%,0)',
backgroundColor: '#fafafa',
height: '30px'
}),
animate(
'300ms cubic-bezier(0.59, 0.32, 0.38, 1.13)',
style({
transform: 'translate(0)',
height: '82px'
})
),
])
)])]
Опишем, что тут происходит:

@.disabled - отключим анимацию элементов при первой загрузке списка.

@fadeExplainMotion - анимируем элемент при добавлении его в dom.

animations: [...] - блок, который описывает поведение анимации. Тут применяются трансформации к dom элементу, изменение заливки и его высоты. А также задается время и функция движения.

Паттерн: объяснение происходящего (What Just Happened), удаление элемента. Этот вид анимации похож на предыдущий и выглядит следующим образом:

Удаление элемента  Angular animation
Удаление элемента Angular animation
Код анимации:

transition(
'* => void',
animation([
style({
backgroundColor: '#fafafa',
height: '82px'
}),
animate(
300ms cubic-bezier(0.59, 0.32, 0.38, 1.13),
style({
transform: 'translate(-25%,0)',
height: '82px'
})
),
])
Код довольно похож за исключением:

* => void - реагируем на удаление элемента из dom

transform: 'translate(-25%,0) - смещает элемент справа на лево

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

Сделаем анимацию переиспользуемой и кастомизируемой для пользователей библиотек с использованием dependency injection​

После изучения многих библиотек компонентов, можно сделать вывод, что анимации удобно складывать в директории "animation" . Например, так делают ребята из TaigaUI и NgZorro. Этот способ нам тоже показался удобным.

Добавим файл "fade-explain.ts", который экспортирует анимацию выше:


const TRANSITION = '{{duration}}ms cubic-bezier(0.59, 0.32, 0.38, 1.13)';
const DURATION = {params: {duration: 300}};

export const fadeExplainMotion: AnimationTriggerMetadata = trigger('fadeExplainMotion', [
transition(
':enter',
animation([
style({
transform: 'translate(25%,0)',
backgroundColor: '#fafafa',
height: '30px'
}),
animate(
TRANSITION,
style({
transform: 'translate(0)',
height: '82px'
})
),
]),
DURATION
),
transition(
'* => void',
animation([
style({
backgroundColor: '#fafafa',
height: '82px'
}),
animate(
TRANSITION,
style({
transform: 'translate(-25%,0)',
height: '82px'
})
),
])
)
]);
Теперь метаданные компонента будут выглядеть следующим образом, анимация может подключается в любые компоненты:


@Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss'],
animations: [fadeExplainMotion, fadeExplainEditMotion, ... ],
})
Этот пример демонстрирует переиспользование. Давайте добавим возможность пользователям библиотек компонентов менять параметры анимации, например скорость. Для этого воспользуемся механизмом dependency injection.

  1. создадим файл "animation-tokens.ts"
  2. Напишем реализацию ANIMATION_OPTIONS
export const ANIMATIONS_DURATION = new InjectionToken<number>(
'Duration of animations in ms',
{
factory: () => 300,
},
);
Получим токен в конструкторе компонента:

constructor(@Inject(ANIMATIONS_DURATION) private readonly duration: number,) {
Создадим переменную в компоненте:

animation = {
value: '', params: {
duration: this.duration
}
};
Привяжем переменную к анимации в шаблоне:

<div
*ngFor='let item of items; index as i; trackBy:id'
[@fadeExplainMotion]='animation'
>
Для изменения параметра скорости анимации нужно добавить в модуль новое значение токена (в раздел providers):

providers: [
{ provide: ANIMATIONS_DURATION, useValue: 350 }
],
Теперь вся команда может использовать единообразные анимации, и при необходимости переопределять свои параметры.

Пример из статьи можно найти по ссылке.

Подборка книг и интересных статей по анимации интерфейсов:

Недавно прошел онлайн workshop "Роман Седов & Александр Инкин | Workshop | DI: две буквы, безграничные возможности." в котором было пару слайдов об анимации и DI.

Interaction Design & Complex Animations - в этой книге можно найти фундаментальные принципы интерактивного дизайна и анимации.

Animation in Design System E-Book - книга рассказывает про анимацию в дизайн системах.

In-Depth guide into animations in Angular - статья подробно описывает анимацию в Angular.

Angular UX Using 4 Animation Techniques - статья с большим набором видео про UX/UI и анимацию на Angular.

Заключение​

В этой статье мы определили роль анимаций в дизайн системах и библиотеках компонентов. Подсветили моменты связанные с их оптимизацией. Рассмотрели паттерны анимаций. Реализовали пару примеров на Angular. И применили механизм dependency injection для повторного использования и кастомизации.

 
Сверху