Кастомные анимации через CSS

Библиотека Noty не реализует анимации самостоятельно — она делегирует их CSS. Это означает, что вся логика появления и скрытия уведомлений строится на добавлении и удалении CSS-классов. Такой подход даёт полный контроль над визуальным поведением уведомлений.

В конфигурации Noty используются два ключевых параметра:

  • animation.open — класс (или список классов), применяемый при показе уведомления
  • animation.close — класс, применяемый при закрытии

Дополнительно:

  • animation.easing — функция плавности (если используется JS-анимация, но чаще не нужна)
  • animation.speed — длительность, но при CSS-анимациях контролируется через animation-duration

Базовая структура CSS-анимации

Любая кастомная анимация строится на основе @keyframes:

@keyframes fadeInCustom {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
@keyframes fadeOutCustom {
  from {
    opacity: 1;
    transform: translateY(0);
  }
  to {
    opacity: 0;
    transform: translateY(-20px);
  }
}

Классы, которые будут использоваться Noty:

.noty-animation-open {
  animation: fadeInCustom 0.5s ease forwards;
}

.noty-animation-close {
  animation: fadeOutCustom 0.4s ease forwards;
}

Подключение кастомных анимаций в Noty

Конфигурация уведомления:

new Noty({
  text: 'Уведомление с кастомной анимацией',
  animation: {
    open: 'noty-animation-open',
    close: 'noty-animation-close'
  }
}).show();

Важно:

  • Noty не проверяет корректность классов
  • Если классы отсутствуют — анимации не будет
  • Если длительность CSS и внутренний таймер не совпадают — возможны визуальные артефакты

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

Можно комбинировать эффекты:

animation: {
  open: 'animated fadeInDown faster',
  close: 'animated fadeOutUp faster'
}

В этом случае Noty просто добавляет строку классов в DOM-элемент.


Анимации через transition

Альтернативный подход — использовать transition вместо @keyframes.

.noty-transition {
  opacity: 0;
  transform: scale(0.9);
  transition: all 0.3s ease;
}

.noty-transition.noty-open {
  opacity: 1;
  transform: scale(1);
}

.noty-transition.noty-close {
  opacity: 0;
  transform: scale(0.9);
}

Тогда потребуется вручную управлять состояниями через дополнительные классы или использовать встроенные хуки Noty.


Управление через lifecycle hooks

Noty предоставляет события жизненного цикла:

  • onShow
  • onClose
  • afterShow
  • afterClose

Пример:

new Noty({
  text: 'Анимация через JS',
  callbacks: {
    onShow: function() {
      this.barDom.classList.add('custom-enter');
    },
    onClose: function() {
      this.barDom.classList.add('custom-exit');
    }
  }
}).show();

CSS:

.custom-enter {
  animation: slideIn 0.4s ease forwards;
}

.custom-exit {
  animation: slideOut 0.4s ease forwards;
}

Анимации с учётом позиции уведомления

Позиция влияет на направление анимации:

  • top → логично анимировать сверху вниз
  • bottom → снизу вверх
  • left/right → горизонтальные движения

Пример универсальной анимации:

@keyframes slideInTop {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(0);
  }
}

@keyframes slideInBottom {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

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

new Noty({
  layout: 'topRight',
  animation: {
    open: 'slide-in-top',
    close: 'fade-out'
  }
});

Работа с transform и GPU-ускорением

Для плавности рекомендуется использовать:

  • transform вместо top/left
  • opacity для появления

Плохо:

top: -100px;

Хорошо:

transform: translateY(-100px);

Это активирует GPU и делает анимацию более плавной.


Комбинирование эффектов

Можно объединять несколько трансформаций:

@keyframes complexIn {
  0% {
    opacity: 0;
    transform: scale(0.8) rotate(-5deg);
  }
  100% {
    opacity: 1;
    transform: scale(1) rotate(0);
  }
}

Использование cubic-bezier

Точная настройка плавности:

animation: fadeInCustom 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55);

Популярные варианты:

  • ease-in-out — стандарт
  • cubic-bezier(0.25, 1, 0.5, 1) — плавное ускорение
  • cubic-bezier(0.68, -0.55, 0.27, 1.55) — эффект “пружины”

Задержки и последовательности

Добавление задержки:

animation: fadeInCustom 0.5s ease 0.2s forwards;

Это полезно при:

  • каскадном появлении уведомлений
  • сложных интерфейсных сценариях

Оптимизация производительности

Ключевые рекомендации:

  • избегать анимации width, height, margin
  • использовать will-change только при необходимости
.noty-animation-open {
  will-change: transform, opacity;
}
  • не использовать слишком длинные анимации
  • избегать тяжёлых теней (box-shadow) во время анимации

Интеграция с animate.css

Можно использовать готовые библиотеки:

animation: {
  open: 'animate__animated animate__fadeInDown',
  close: 'animate__animated animate__fadeOutUp'
}

Важно:

  • библиотека должна быть подключена
  • классы должны соответствовать версии

Анимации для разных типов уведомлений

Разные типы можно визуально разделять:

.noty_type__success {
  animation: successPop 0.4s ease;
}

.noty_type__error {
  animation: errorShake 0.5s ease;
}

Пример shake-анимации:

@keyframes errorShake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-5px); }
  75% { transform: translateX(5px); }
}

Управление временем жизни и анимацией

Важно синхронизировать:

  • timeout уведомления
  • длительность закрывающей анимации

Если анимация закрытия длится 500ms:

timeout: 3000

Noty автоматически учитывает закрытие, но при сложных сценариях возможны задержки.


Debug и отладка

Полезные приёмы:

  • временно увеличить animation-duration
  • использовать outline для проверки позиции
  • проверять наличие классов в DevTools

Распространённые ошибки

  • отсутствие forwards в animation → элемент возвращается в исходное состояние
  • несовпадение имени класса в JS и CSS
  • конфликт с внешними библиотеками
  • слишком короткая длительность (анимация не видна)

Создание собственной системы анимаций

Организация:

/* Базовые */
.noty-anim-fade-in {}
.noty-anim-fade-out {}

/* Направления */
.noty-anim-slide-top {}
.noty-anim-slide-bottom {}

/* Типы */
.noty-anim-success {}
.noty-anim-error {}

Комбинирование:

animation: {
  open: 'noty-anim-fade-in noty-anim-slide-top',
  close: 'noty-anim-fade-out'
}

Такой подход масштабируется и упрощает поддержку проекта.