Управление поведением переворота

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

Ключевой момент заключается в использовании middleware flip, которое проверяет доступное пространство вокруг опоры и при необходимости изменяет сторону размещения.

import { computePosition, flip } from '@floating-ui/dom';

computePosition(referenceElement, floatingElement, {
  middleware: [flip()]
}).then(({ x, y }) => {
  Object.assign(floatingElement.style, {
    left: `${x}px`,
    top: `${y}px`
  });
});

В этом примере flip() автоматически проверяет все четыре направления (top, right, bottom, left) и выбирает оптимальное, если изначально заданное направление не помещается.


Настройка опций flip

Middleware flip принимает объект конфигурации с несколькими ключевыми параметрами:

  • fallbackPlacements — массив альтернативных направлений, которые будут проверяться по порядку, если основное направление не подходит.

  • fallbackStrategy — стратегия выбора fallback-направления:

    • "bestFit" — выбирается вариант с наибольшим доступным пространством.
    • "initialPlacement" — возвращается к исходной позиции, если она частично помещается.
  • boundary — элемент или объект, ограничивающий пространство для всплывающего элемента. По умолчанию используется viewport.

  • padding — отступ от границ boundary, предотвращающий прилипание к краю экрана.

Пример с кастомными fallback-направлениями:

computePosition(referenceElement, floatingElement, {
  placement: 'top',
  middleware: [flip({
    fallbackPlacements: ['right', 'bottom', 'left'],
    boundary: document.body,
    padding: 8
  })]
});

Здесь при невозможности разместить элемент сверху, библиотека проверяет по очереди: справа, снизу и слева, с отступом 8 пикселей от границ body.


Интеграция с другими middleware

flip часто используется совместно с shift и offset для точного позиционирования:

  • shift корректирует элемент, если он выходит за границы boundary, не меняя его направления.
  • offset добавляет смещение относительно опоры.

Пример комплексного позиционирования:

computePosition(referenceElement, floatingElement, {
  placement: 'bottom',
  middleware: [
    offset(10),
    flip({ fallbackPlacements: ['top', 'right'] }),
    shift({ padding: 5 })
  ]
});

Последовательность middleware критична: сначала определяется смещение (offset), затем выполняется проверка переворота (flip), а затем корректировка по границам (shift). Такой порядок обеспечивает предсказуемое поведение даже при ограниченном пространстве.


Контроль поведения при ограниченном пространстве

Иногда важно задать ограничение на количество попыток переворота или принудительно блокировать некоторые направления. Для этого используется сочетание flip с пользовательскими fallbackPlacements и boundary. Например, можно запретить всплывающему элементу появляться слева и сверху:

flip({
  fallbackPlacements: ['right', 'bottom']
});

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


Отслеживание и динамическое обновление позиции

Для интерактивных интерфейсов важно, чтобы элемент реагировал на изменение размеров или прокрутку окна. Floating UI предоставляет функцию autoUpdate, которая отслеживает изменения и повторно вычисляет позицию:

import { autoUpdate } from '@floating-ui/dom';

autoUpdate(referenceElement, floatingElement, () => {
  computePosition(referenceElement, floatingElement, {
    middleware: [flip(), shift(), offset(5)]
  }).then(({ x, y }) => {
    Object.assign(floatingElement.style, { left: `${x}px`, top: `${y}px` });
  });
});

Сочетание flip и autoUpdate гарантирует, что даже при изменении размеров окна или движения опоры всплывающий элемент останется видимым и корректно расположен.


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

  • Всегда указывать fallbackPlacements, чтобы исключить неожиданные перекрытия или обрезку контента.
  • Использовать boundary и padding, чтобы предотвратить “залипание” элементов к краям экрана.
  • Комбинировать с offset и shift для плавного и предсказуемого позиционирования.
  • Использовать autoUpdate при динамических интерфейсах, чтобы избежать ручного пересчёта позиции.

Эти приёмы позволяют полностью контролировать поведение переворота, обеспечивая стабильность и адаптивность интерфейсов с плавающими элементами.