Библиотека Floating UI предоставляет мощный набор инструментов для
управления позиционированием плавающих элементов в браузере, таких как
тултипы, всплывающие окна и контекстные меню. Важной особенностью
является возможность создавать кастомные стратегии
позиционирования, выходящие за рамки стандартных алгоритмов
(flip, shift, offset), что
особенно полезно для сложных интерфейсов и нестандартных макетов.
computePositioncomputePosition — центральная функция Floating UI,
которая вычисляет координаты плавающего элемента относительно якоря. Она
принимает два обязательных параметра: reference
(элемент, к которому привязан флоатинг) и floating (сам
флоатинг). Также поддерживается объект с опциями:
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');
computePosition(reference, floating, {
placement: 'top',
middleware: [offset(10), flip(), shift({ padding: 5 })],
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`,
});
});
Ключевые моменты:
placement задаёт базовое направление (top,
bottom, left, right) с
опциональными вариациями (-start, -end).middleware позволяет добавлять цепочку функций для
изменения поведения позиционирования.Middleware — это функции, которые получают текущие координаты и могут их модифицировать. Например, можно создать middleware для ограничения перемещения флоатинга в пределах видимой области:
function restrictToViewport() {
return {
name: 'restrictToViewport',
fn({ x, y, rects, placement }) {
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let newX = Math.min(Math.max(0, x), viewportWidth - rects.floating.width);
let newY = Math.min(Math.max(0, y), viewportHeight - rects.floating.height);
return { x: newX, y: newY };
},
};
}
computePosition(reference, floating, {
placement: 'bottom',
middleware: [restrictToViewport()],
});
Такой подход позволяет полностью контролировать позицию элемента, независимо от стандартных правил.
Кастомная логика часто требует смены позиции в зависимости от условий страницы:
function dynamicPlacement() {
return {
name: 'dynamicPlacement',
fn({ placement, rects }) {
if (rects.reference.top < 100) return { data: { placement: 'bottom' } };
return { data: { placement } };
},
};
}
computePosition(reference, floating, {
placement: 'top',
middleware: [dynamicPlacement(), offset(8)],
});
Middleware может возвращать не только новые координаты, но и данные, которые могут использоваться другими middleware для сложной логики.
Floating UI поддерживает любые системы координат, включая скроллируемые контейнеры и трансформированные элементы. Для этого используется strategy:
absolute — позиционирование относительно документа,
учитывая скролл.fixed — позиционирование относительно окна, игнорируя
скролл.computePosition(reference, floating, {
placement: 'right',
strategy: 'fixed',
});
Это особенно важно для модальных окон, которые должны оставаться на месте при прокрутке родительских элементов.
Можно комбинировать стандартные middleware и свои функции. Например, создать флоатинг, который подсказывает направление пользователя и ограничивается viewport:
computePosition(reference, floating, {
placement: 'top',
middleware: [
offset(5),
flip(),
shift({ padding: 10 }),
restrictToViewport(),
dynamicPlacement(),
],
});
Порядок middleware имеет значение: каждая последующая функция получает координаты после обработки предыдущих.
data объект для сложных цепочек.strategy осознанно,
особенно для фиксированных элементов и скроллируемых контейнеров.Middleware обычно имеет следующий формат:
{
name: 'название',
options: { ... }, // при необходимости
async fn({ x, y, placement, rects, middlewareData }) {
// вычисления
return { x: newX, y: newY, data: { ... } };
}
}
rects — объект с размерами reference и floating.middlewareData — данные от предыдущих middleware.x, y,
data, или reset для пересчёта с новым
placement.Кастомная логика позиционирования в Floating UI превращает библиотеку из простого тултипа в полноценный инструмент для создания адаптивных и сложных интерфейсов. Гибкость middleware и поддержка различных стратегий позволяют решать практически любые задачи визуального позиционирования на страницах любого уровня сложности.