Анимации и transitions

Popper.js изначально разрабатывался как библиотека для управления позиционированием всплывающих элементов (popper) относительно целевых элементов (reference). Несмотря на то, что Popper.js сам по себе не предоставляет встроенных средств анимации, он обеспечивает гибкие механизмы, которые позволяют интегрировать CSS-анимации и transitions без нарушения корректного позиционирования.

Ключевая идея заключается в том, что Popper.js динамически управляет позициями и стилями элементов через JavaScript, но не вмешивается в визуальные эффекты появления, исчезновения или движения. Поэтому анимации строятся на уровне CSS, а Popper.js обеспечивает стабильность положения элементов.


Использование CSS transitions с Popper.js

Для базовой анимации всплывающих элементов чаще всего применяется свойство transition в CSS. Рассмотрим пример плавного появления и исчезновения:

.popper {
  opacity: 0;
  transform: scale(0.95);
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.popper[data-show] {
  opacity: 1;
  transform: scale(1);
}
  • .popper — основной элемент popper.
  • opacity и transform управляют визуальным эффектом появления.
  • Атрибут data-show добавляется и удаляется через JavaScript, управляя состоянием анимации.

В JavaScript необходимо синхронизировать атрибут с жизненным циклом Popper.js:

import { createPopper } from '@popperjs/core';

const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');

const popperInstance = createPopper(button, tooltip, {
  placement: 'top',
});

function show() {
  tooltip.setAttribute('data-show', '');
  popperInstance.update();
}

function hide() {
  tooltip.removeAttribute('data-show');
}

Важный момент: popperInstance.update() гарантирует, что позиция будет пересчитана после изменений DOM, что предотвращает дрожание или смещение во время анимации.


Интеграция с анимационными библиотеками

Популярные библиотеки для анимаций, такие как GSAP или Anime.js, могут использоваться совместно с Popper.js для более сложных эффектов. Ключевая стратегия: Popper.js управляет позиционированием, а внешняя библиотека — визуальными эффектами.

Пример с GSAP:

import { gsap } from 'gsap';
import { createPopper } from '@popperjs/core';

const button = document.querySelector('#button');
const tooltip = document.querySelector('#tooltip');

const popperInstance = createPopper(button, tooltip, { placement: 'bottom' });

function show() {
  popperInstance.update();
  gsap.to(tooltip, { opacity: 1, y: 0, duration: 0.3 });
}

function hide() {
  gsap.to(tooltip, { opacity: 0, y: -10, duration: 0.3 });
}
  • y — вертикальное смещение элемента.
  • popperInstance.update() вызывается перед анимацией, чтобы позиция элемента была актуальной.
  • Анимация не мешает Popper.js рассчитывать столкновения и смещения относительно окна или контейнера.

Анимация при смене позиции

Popper.js поддерживает динамическое изменение placement и автоматическое обновление позиции при изменении контекста. Для плавного визуального перехода можно использовать CSS-переходы:

.popper {
  transition: transform 0.2s ease;
}
popperInstance.setOptions({
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['top', 'right', 'bottom', 'left'],
      },
    },
  ],
});

Когда flip изменяет позицию popper, CSS transition создаёт эффект мягкого смещения без рывков. Этот приём особенно эффективен для адаптивных интерфейсов и всплывающих подсказок, меняющих ориентацию при изменении размера окна.


Контроль появления через lifecycle

Для сложных сценариев анимации полезно использовать события жизненного цикла Popper.js через модификаторы. Например, модификатор eventListeners позволяет синхронизировать анимацию с событиями scroll и resize:

const popperInstance = createPopper(button, tooltip, {
  modifiers: [
    {
      name: 'eventListeners',
      options: { scroll: true, resize: true },
    },
  ],
});
  • scroll: true — обновление позиции при прокрутке.
  • resize: true — обновление позиции при изменении размеров окна.

Это позволяет безопасно применять CSS-анимации, не опасаясь, что popper “вылетит” за границы видимой области.


Работа с opacity и visibility

Для создания плавного появления и исчезновения всплывающих элементов лучше комбинировать opacity и visibility:

.popper {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease;
}

.popper[data-show] {
  opacity: 1;
  visibility: visible;
}
  • opacity управляет визуальным эффектом.
  • visibility исключает кликабельность элемента, пока он скрыт.
  • Использование data-show обеспечивает контроль через JavaScript без вмешательства в вычисления Popper.js.

Практические рекомендации

  • Всегда вызывать popperInstance.update() перед началом анимации, чтобы popper был на актуальной позиции.
  • Для сложных анимаций лучше использовать внешние библиотеки, оставляя Popper.js только для расчёта позиции.
  • Анимация transform предпочтительнее top/left, так как она аппаратно ускорена и не вызывает пересчёта layout.
  • Сочетать transitions с атрибутом data-show или классами для управления состоянием появления.
  • При динамической смене placement использовать CSS-переходы для плавного смещения.

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