Viewport constraints

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


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

Вьюпорт в контексте Floating UI — это область, внутри которой пользователь видит содержимое страницы без прокрутки. Обычно это размер окна браузера, но можно использовать кастомные контейнеры с прокруткой (scrollable parents).

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

  • flip
  • shift
  • autoPlacement
  • offset (частично, для управления расстоянием от границ)
  • detectOverflow (низкоуровневый инструмент для расчёта переполнения)

Middleware flip

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

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

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

Ключевые моменты flip:

  • fallbackPlacements задаёт последовательность альтернативных позиций, если основной вариант не помещается.
  • Позиции выбираются динамически на основе расчёта переполнения (detectOverflow).
  • Можно комбинировать с shift, чтобы дополнительно смещать элемент внутрь видимой области.

Middleware shift

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

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

computePosition(referenceElement, floatingElement, {
  placement: 'bottom-start',
  middleware: [shift({padding: 8})],
}).then(({x, y}) => {
  Object.assign(floatingElement.style, {
    left: `${x}px`,
    top: `${y}px`,
  });
});

Особенности shift:

  • padding задаёт минимальное расстояние до границ вьюпорта.
  • Работает совместно с flip, обеспечивая корректное позиционирование даже при смене стороны.
  • Позволяет избежать ситуации, когда элемент «обрезается» краем экрана.

Middleware autoPlacement

autoPlacement объединяет возможности flip и shift, предоставляя комплексное решение для динамического выбора позиции:

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

computePosition(referenceElement, floatingElement, {
  middleware: [
    autoPlacement({
      alignment: 'start',
      allowedPlacements: ['top', 'bottom', 'right', 'left'],
      padding: 10
    })
  ],
}).then(({x, y, placement}) => {
  Object.assign(floatingElement.style, {
    left: `${x}px`,
    top: `${y}px`,
  });
});

Преимущества autoPlacement:

  • Выбирает оптимальное место для всплывающего элемента с учётом переполнения.
  • Позволяет указать ограничения на допустимые позиции через allowedPlacements.
  • Автоматически учитывает смещение (shift) при необходимости.

Низкоуровневый контроль с detectOverflow

detectOverflow предоставляет точные данные о том, насколько элемент выходит за пределы контейнера или вьюпорта. Его можно использовать для кастомной логики позиционирования:

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

const overflow = await detectOverflow(floatingElement, {boundary: document.documentElement});
console.log(overflow); // {top: 0, bottom: 50, left: 0, right: 20}

Важные детали:

  • Возвращает объект с переполнением по каждой стороне.
  • Может использоваться для вычисления смещения или динамического изменения размера.
  • Поддерживает кастомные границы через параметр boundary.

Настройка границ вьюпорта

Floating UI позволяет задавать кастомные контейнеры для ограничения элементов:

computePosition(referenceElement, floatingElement, {
  middleware: [shift({boundary: document.querySelector('#scrollable-container')})]
});
  • Параметр boundary может быть:

    • Элемент DOM (ограничение внутри контейнера)
    • viewport (по умолчанию)
    • Функция, возвращающая кастомный элемент
  • В сочетании с padding позволяет тонко управлять расстоянием до краёв контейнера.


Советы по практическому использованию

  • Комбинация middleware: Для большинства интерфейсов рекомендуется использовать комбинацию flip + shift, чтобы элемент корректно менял сторону и оставался внутри видимой области.
  • Динамический выбор позиции: autoPlacement упрощает логику для сложных интерфейсов, особенно с элементами разной высоты или ширины.
  • Учёт прокрутки: Если всплывающий элемент находится внутри scrollable container, обязательно указывать boundary, иначе элемент может выходить за пределы контейнера.
  • Минимизация смещения: Использовать padding и offset для того, чтобы элемент не прилипал к краям и оставался читаемым.

Заключение по ограничению вьюпорта

Использование middleware flip, shift и autoPlacement вместе с detectOverflow позволяет создавать гибкие и адаптивные интерфейсы. Ограничение всплывающих элементов границами вьюпорта делает интерфейс безопасным и предотвращает обрезание контента. Floating UI предоставляет точный и настраиваемый механизм управления переполнением, который подходит для всех типов всплывающих элементов.