Автоматическая смена стороны размещения

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


Основные концепции

1. reference и floating элементы reference — это элемент, относительно которого позиционируется всплывающее окно. floating — это сам всплывающий элемент, который может изменять своё положение в зависимости от доступного пространства.

2. middleware flip flip — это middleware, встроенный в Floating UI, отвечающий за смену стороны размещения. Он анализирует доступное пространство вокруг reference и при необходимости меняет позицию floating.

Пример использования middleware flip:

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

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

computePosition(reference, floating, {
  placement: 'top',
  middleware: [offset(8), flip()]
}).then(({ x, y, placement }) => {
  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`
  });
});

В этом примере:

  • placement: 'top' — изначально всплывающее окно расположено над кнопкой.
  • offset(8) — отступ 8 пикселей от reference.
  • flip() — автоматически проверяет, помещается ли элемент сверху, и при необходимости переключает на доступную сторону (например, снизу, слева или справа).

Параметры middleware flip

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

flip({
  fallbackPlacements: ['bottom', 'right', 'left'],
  boundary: document.body,
  padding: 5
})
  • fallbackPlacements — массив альтернативных позиций, которые будут проверяться по порядку, если исходная недоступна.
  • boundary — элемент, который ограничивает доступное пространство для floating. По умолчанию это viewport.
  • padding — минимальное расстояние от границы boundary до floating.

Пример с пользовательскими fallback-позициями:

computePosition(reference, floating, {
  placement: 'top',
  middleware: [
    offset(10),
    flip({
      fallbackPlacements: ['bottom', 'right', 'left'],
      padding: 12
    })
  ]
});

Здесь floating будет пытаться сначала оставаться сверху, затем проверять низ, правую и левую стороны до нахождения оптимального положения.


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

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

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

autoUpdate(reference, floating, () => {
  computePosition(reference, floating, {
    placement: 'top',
    middleware: [offset(10), flip()]
  }).then(({ x, y }) => {
    Object.assign(floating.style, {
      left: `${x}px`,
      top: `${y}px`
    });
  });
});

autoUpdate отслеживает изменения позиции и размеров элементов, автоматически вызывая пересчёт с middleware flip. Таким образом, floating всегда остаётся в видимой области.


Настройка поведения при ограниченном пространстве

Иногда требуется контролировать, как flip выбирает сторону:

  • Только вертикальные варианты:

    flip({ fallbackPlacements: ['bottom', 'top'] })
  • Только горизонтальные варианты:

    flip({ fallbackPlacements: ['right', 'left'] })
  • Динамическое определение границы:

    flip({ boundary: () => document.querySelector('#container') })

Также можно комбинировать flip с другими middleware, например shift, чтобы элемент дополнительно смещался внутри видимой области при ограниченном пространстве:

computePosition(reference, floating, {
  placement: 'top',
  middleware: [offset(10), flip(), shift({ padding: 5 })]
});

shift корректирует положение floating, если даже после flip оно частично выходит за границы окна.


Практические советы

  • Всегда указывать fallbackPlacements — это позволяет контролировать порядок смены стороны.
  • Использовать padding для предотвращения прилипания к границе — особенно важно для мобильных интерфейсов.
  • Комбинировать с shift — повышает визуальную стабильность при ограниченном пространстве.
  • Подключать autoUpdate — для адаптивных интерфейсов с динамическими изменениями DOM.

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