Подгонка под доступное пространство

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


Определение ограничений пространства

Floating UI использует концепцию overflow boundaries — границ, за которыми элемент не должен выходить. Эти границы могут быть:

  • Видимой областью окна браузера (viewport) Используется для предотвращения выхода элемента за пределы экрана.
  • Контейнером (clipping ancestor) Позволяет ограничивать позицию всплывающего элемента рамками родительского блока с overflow: hidden, scroll или auto.

Для задания границ применяется опция middleware, где можно использовать встроенные функции, такие как flip, shift и size.


Flip: автоматическое переворачивание

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

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

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

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

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

  • Проверяет доступное пространство по выбранной оси.
  • Если на заданной стороне недостаточно места, пытается расположить элемент на противоположной стороне.
  • Можно задавать список приоритетных позиций:
flip({ fallbackPlacements: ['top', 'right', 'left'] });

Shift: смещение внутри доступной области

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

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

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

Параметры:

  • padding — минимальное расстояние от границ.
  • Можно комбинировать с flip для более гибкого поведения.

Size: адаптивные размеры

Мидлвар size позволяет динамически изменять размеры всплывающего элемента в зависимости от доступного пространства:

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

computePosition(reference, floating, {
  placement: 'bottom',
  middleware: [
    size({
      apply({ availableWidth, availableHeight, elements }) {
        Object.assign(elements.floating.style, {
          maxWidth: `${availableWidth}px`,
          maxHeight: `${availableHeight}px`,
        });
      },
    }),
  ],
});

Принципы работы:

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

Комбинирование мидлваров

Для полноценного управления пространством рекомендуется использовать цепочку мидлваров. Порядок имеет значение:

computePosition(reference, floating, {
  placement: 'bottom-start',
  middleware: [
    flip({ fallbackPlacements: ['top-start', 'right-start'] }),
    shift({ padding: 10 }),
    size({
      apply({ availableWidth, elements }) {
        elements.floating.style.maxWidth = `${availableWidth}px`;
      },
    }),
  ],
});

Пояснения:

  1. Flip пытается изменить сторону, если нет места.
  2. Shift подгоняет позицию внутри выбранной стороны.
  3. Size ограничивает размеры, чтобы элемент полностью помещался в доступной области.

Динамическое обновление при изменении экрана

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

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

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

Таким образом, всплывающий элемент остаётся корректно позиционированным в любой ситуации.


Рекомендации по подгонке под пространство

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

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