Анимация появления и исчезновения

Floating UI — это мощная библиотека для создания позиционируемых элементов интерфейса, таких как тултипы, поповеры и дропдауны. Управление их анимацией требует понимания жизненного цикла отображаемого элемента, взаимодействия с DOM и интеграции CSS или JS-анимаций.

Контроль жизненного цикла

Каждый floating-элемент имеет следующие состояния:

  • Открыт: элемент отображается на экране и полностью доступен для взаимодействия.
  • Закрыт: элемент отсутствует в DOM или скрыт через CSS (display: none или opacity: 0).
  • Переходный: элемент находится в процессе анимации появления или исчезновения.

Для корректной анимации важно использовать transition hooks, которые позволяют запускать анимацию перед добавлением элемента в DOM или перед его удалением.

import { useFloating } from '@floating-ui/react';

const { floatingStyles, context } = useFloating({
  placement: 'bottom',
});

Здесь floatingStyles можно расширить с помощью анимационных классов, чтобы управлять переходами состояния элемента.

CSS-анимации появления и исчезновения

Наиболее простая и производительная стратегия — использование CSS-переходов для изменения прозрачности и трансформаций.

.floating-enter {
  opacity: 0;
  transform: translateY(-10px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.floating-enter-active {
  opacity: 1;
  transform: translateY(0);
}

.floating-exit {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.floating-exit-active {
  opacity: 0;
  transform: translateY(-10px);
}
  • opacity управляет прозрачностью.
  • transform создаёт плавный эффект смещения.
  • transition задаёт длительность и кривую анимации.

Интеграция с JS

Для более точного контроля анимаций применяются JavaScript-функции, которые управляют классами или стилями в зависимости от событий open и close.

import { useState, useEffect } from 'react';
import { useFloating } from '@floating-ui/react';

function Tooltip({ referenceElement, content }) {
  const { x, y, reference, floating, strategy } = useFloating({ placement: 'top' });
  const [isVisible, setIsVisible] = useState(false);

  useEffect(() => {
    if (isVisible) {
      floating.current.classList.add('floating-enter');
      requestAnimationFrame(() => {
        floating.current.classList.add('floating-enter-active');
      });
    } else if (floating.current) {
      floating.current.classList.add('floating-exit');
      requestAnimationFrame(() => {
        floating.current.classList.add('floating-exit-active');
      });
    }
  }, [isVisible]);

  return (
    <div ref={floating} style={{ position: strategy, top: y ?? 0, left: x ?? 0 }}>
      {content}
    </div>
  );
}
  • requestAnimationFrame гарантирует, что браузер правильно отработает изменения классов и запустит transition.
  • Состояние isVisible позволяет синхронизировать появление/исчезновение с внутренним состоянием Floating UI.

Анимация с использованием библиотеки Framer Motion

Для сложных анимаций часто применяют сторонние анимационные библиотеки, такие как Framer Motion, позволяющие создавать масштабные эффекты появления, движения и вращения.

import { motion, AnimatePresence } from 'framer-motion';

<AnimatePresence>
  {isVisible && (
    <motion.div
      initial={{ opacity: 0, y: -10 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0, y: -10 }}
      transition={{ duration: 0.2 }}
      ref={floating}
      style={{ position: strategy, top: y ?? 0, left: x ?? 0 }}
    >
      {content}
    </motion.div>
  )}
</AnimatePresence>
  • initial — стартовое состояние анимации.
  • animate — конечное состояние при появлении.
  • exit — состояние при исчезновении.
  • transition — параметры времени и кривой движения.

Синхронизация с позиционированием

Floating UI вычисляет точное положение элемента, учитывая размеры, окно просмотра и смещения. Для плавных анимаций важно не менять позицию элемента во время анимации, иначе появятся рывки. Лучший способ — анимировать только opacity, scale, translate и не трогать координаты top и left до завершения анимации.

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

  • Использовать transition на CSS-свойствах, которые не вызывают перерисовку макета (opacity, transform).
  • Сохранять floating-элемент в DOM до окончания анимации исчезновения.
  • Комбинировать с JS-хуками для полного контроля над состоянием.
  • Для сложных анимаций применять анимационные библиотеки с AnimatePresence или аналогами, чтобы управлять lifecycle элементов.

Особенности работы с задержками и цепочками анимаций

Floating UI поддерживает вложенные floating-элементы (например, меню внутри тултипа). В таких случаях анимации должны синхронизироваться, чтобы дочерние элементы появлялись после родительских или исчезали перед ними. Используются setTimeout или анимационные библиотеки с поддержкой последовательных переходов.


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