Функция computePosition

Функция computePosition является ядром библиотеки Floating UI и отвечает за вычисление точного положения плавающих элементов относительно их целевых якорей (reference elements). Она возвращает координаты x и y для абсолютного позиционирования элемента, а также дополнительные данные, которые позволяют гибко управлять поведением попапов, тултипов, dropdown-меню и других интерфейсных компонентов.

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

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

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

В этом примере computePosition рассчитывает координаты всплывающего элемента так, чтобы он оказался над кнопкой (placement: 'top').


Параметры функции

reference и floating

  • reference — DOM-элемент или объект, представляющий привязку (anchor).
  • floating — DOM-элемент, который позиционируется.

Объект настроек

computePosition принимает третий аргумент — объект с параметрами конфигурации:

  • placement: 'top' | 'bottom' | 'left' | 'right' с возможными вариантами '-start' и '-end'.
  • strategy: 'absolute' | 'fixed' — определяет стратегию позиционирования.
  • middleware: массив функций, модифицирующих поведение и возвращаемые координаты.

Middleware

Middleware — это функции, которые расширяют возможности позиционирования, корректируют координаты и управляют видимостью элемента.

Популярные middleware

  1. offset — задаёт смещение элемента относительно reference.
import { offset } from '@floating-ui/dom';

computePosition(reference, floating, {
  placement: 'bottom',
  middleware: [offset(10)]
});

Элемент будет смещён на 10 пикселей вниз.

  1. flip — позволяет менять позицию, если элемент выходит за границы viewport.
import { flip } from '@floating-ui/dom';

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

Если сверху нет места, тултип автоматически перейдёт вниз.

  1. shift — корректирует положение, чтобы элемент полностью помещался в видимую область.
import { shift } from '@floating-ui/dom';

computePosition(reference, floating, {
  placement: 'left',
  middleware: [shift({ padding: 5 })]
});

Сдвиг происходит с учётом padding, предотвращая обрезание.

  1. arrow — позиционирует стрелку внутри плавающего элемента.
import { arrow } from '@floating-ui/dom';

const arrowElement = document.querySelector('#arrow');

computePosition(reference, floating, {
  placement: 'top',
  middleware: [arrow({ element: arrowElement })]
});

Возвращает объект x и y для корректного позиционирования стрелки.


Асинхронная обработка

computePosition возвращает Promise, что позволяет использовать async/await для упрощения кода:

async function updatePosition() {
  const { x, y, placement } = await computePosition(reference, floating, {
    placement: 'bottom',
    middleware: [offset(5), flip(), shift()]
  });

  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`
  });
}

Асинхронность особенно важна при работе с динамическими элементами или при расчёте позиций внутри сложных контейнеров.


Возвращаемые значения

Объект, который возвращает computePosition, содержит:

  • x — координата слева для плавающего элемента.
  • y — координата сверху.
  • placement — окончательная позиция после работы middleware (может отличаться от исходной, если сработал flip).
  • middlewareData — объект с результатами всех middleware, например, позиции стрелки.
{
  x: 100,
  y: 50,
  placement: 'top',
  middlewareData: {
    arrow: { x: 10, y: 0 },
    shift: { x: 5, y: 0 }
  }
}

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

  • absolute — элемент позиционируется относительно ближайшего родителя с position: relative или absolute.
  • fixed — элемент фиксируется относительно viewport, игнорируя прокрутку контейнеров.
computePosition(reference, floating, {
  strategy: 'fixed',
  placement: 'right'
});

Используется для модальных окон и тултипов, которые должны оставаться на месте при скролле страницы.


Комбинирование middleware

Middleware можно комбинировать для достижения сложного поведения:

computePosition(reference, floating, {
  placement: 'top-start',
  middleware: [
    offset(8),
    flip({ fallbackPlacements: ['bottom-start', 'bottom-end'] }),
    shift({ padding: 10 }),
    arrow({ element: arrowElement })
  ]
});

Порядок имеет значение: offset применяется первым, flip — вторым, и так далее. Это позволяет точно контролировать результат.


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

  • Всегда использовать flip и shift для адаптивного позиционирования.
  • Для стрелок применять middleware arrow, а координаты брать из middlewareData.arrow.
  • Для элементов, которые остаются на месте при скролле, использовать стратегию fixed.
  • Middleware можно создавать самостоятельно для особых эффектов (например, ограничение позиции по кастомным правилам).

computePosition предоставляет полный контроль над позиционированием интерфейсных элементов, объединяя простоту API с мощной системой middleware для сложных сценариев.