Adaptive positioning strategies

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

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


Стратегии позиционирования

1. absolute и fixed

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

Использование стратегии задаётся через опцию strategy при вызове computePosition:

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

computePosition(referenceElement, floatingElement, {
  strategy: 'fixed',
});

Middleware для адаптивного позиционирования

1. offset

Позволяет задать смещение плавающего элемента от reference:

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

computePosition(reference, floating, {
  middleware: [offset(10)] // смещаем на 10px
});

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

  • Можно задавать фиксированное значение или функцию, возвращающую динамическое смещение.
  • Применяется как горизонтальное, так и вертикальное смещение.

2. flip

Обеспечивает автоматический поворот элемента при нехватке пространства:

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

computePosition(reference, floating, {
  middleware: [flip()]
});

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

  • Работает с несколькими направлениями (top, bottom, left, right).
  • Можно указать приоритет направлений: flip({ fallbackPlacements: ['right', 'left'] }).

3. shift

Сдвигает элемент внутрь видимой области, если часть выходит за границы:

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

computePosition(reference, floating, {
  middleware: [shift({ padding: 8 })] // отступ от границ viewport
});

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

4. size

Позволяет адаптировать размеры floating-элемента в зависимости от доступного пространства:

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

computePosition(reference, floating, {
  middleware: [size({
    apply({ rects, availableHeight, elements }) {
      elements.floating.style.maxHeight = `${availableHeight}px`;
    }
  })]
});
  • availableHeight и availableWidth вычисляются автоматически.
  • Можно использовать для ограничения размера модальных окон, тултипов и меню.

Комплексное использование middleware

Для реальных интерфейсов часто применяется комбинация нескольких middleware:

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

computePosition(reference, floating, {
  strategy: 'absolute',
  placement: 'bottom',
  middleware: [
    offset(8),
    flip({ fallbackPlacements: ['top', 'right'] }),
    shift({ padding: 5 }),
    size({
      apply({ availableHeight, elements }) {
        elements.floating.style.maxHeight = `${availableHeight}px`;
      }
    })
  ]
});

Преимущества такой схемы:

  • Элемент всегда видим.
  • Автоматически меняет направление при нехватке места.
  • Размер адаптируется под экран.
  • Сохраняется отступ от границ.

Dynamic positioning с событиями

Floating UI поддерживает реакцию на изменения DOM и скролл через autoUpdate:

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

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

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

  • Позиция пересчитывается при скролле, ресайзе, изменении размеров reference или floating.
  • Возвращает функцию очистки, чтобы прекратить обновления, когда элемент удаляется из DOM.

Адаптивное поведение на мобильных устройствах

  • Использование shift и flip критично при маленьких экранах.
  • size позволяет ограничивать размеры и предотвращает переполнение.
  • Для touch-интерфейсов часто комбинируют fixed стратегию с динамическим смещением.
computePosition(reference, floating, {
  strategy: 'fixed',
  placement: 'bottom',
  middleware: [offset(5), flip(), shift({ padding: 10 }), size({ padding: 10 })]
});
  • Минимальный отступ гарантирует, что элементы не будут загораживать системные элементы или края экрана.

Советы по производительности

  • Middleware вычисляются каждый кадр при использовании autoUpdate, поэтому тяжёлые операции в apply следует минимизировать.
  • Для больших списков или часто обновляемых элементов можно использовать requestAnimationFrame внутри apply.
  • Комбинация flip + shift + size обеспечивает максимальную адаптивность без ручного пересчёта.

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