Floating UI решает задачу точного позиционирования «плавающих» элементов (tooltip, dropdown, popover) относительно опорного элемента. Ключевая особенность библиотеки — вычисление координат не через жёсткие значения, а через адаптивную систему, учитывающую размеры, прокрутку, границы окна и вложенные контейнеры.
Базовая функция позиционирования:
import { computePosition } from '@floating-ui/dom';
computePosition(referenceEl, floatingEl).then(({ x, y }) => {
Object.assign(floatingEl.style, {
left: `${x}px`,
top: `${y}px`,
});
});
Здесь:
referenceEl — элемент-источник (якорь)floatingEl — плавающий элементx, y — вычисленные координатыPlacement определяет, где относительно reference-элемента будет находиться floating-элемент.
Базовые направления:
topbottomleftrightС выравниванием:
top-starttop-endbottom-startbottom-end и т.д.Пример:
computePosition(referenceEl, floatingEl, {
placement: 'bottom-start',
});
Выравнивание:
start — по левому или верхнему краюend — по правому или нижнему краюОсобенность: направление зависит от writing mode (LTR/RTL).
Размещение не ограничивается простым выбором стороны. Floating UI учитывает:
Если элемент не помещается, используются middleware для корректировки.
Middleware — цепочка функций, модифицирующих результат позиционирования.
Подключение:
import { offset, flip, shift } from '@floating-ui/dom';
computePosition(referenceEl, floatingEl, {
middleware: [
offset(8),
flip(),
shift(),
],
});
Позволяет задать отступ между элементами.
offset(10)
Можно задавать:
offset({
mainAxis: 10,
crossAxis: 5,
});
Где:
mainAxis — направление размещения (например, вниз для
bottom)crossAxis — перпендикулярная осьМеняет сторону, если элемент не помещается.
flip()
Пример:
bottomtopРасширенная настройка:
flip({
fallbackPlacements: ['top', 'right'],
});
Предотвращает выход за пределы viewport.
shift()
Работает даже при фиксированном placement:
Настройка:
shift({
padding: 8,
});
Порядок middleware критически важен:
middleware: [
offset(8),
flip(),
shift(),
]
Почему:
Неверный порядок может привести к визуальным артефактам.
Позволяет адаптировать размеры floating-элемента под доступное пространство.
import { size } from '@floating-ui/dom';
size({
apply({ availableWidth, availableHeight, elements }) {
Object.assign(elements.floating.style, {
maxWidth: `${availableWidth}px`,
maxHeight: `${availableHeight}px`,
});
},
});
Используется для:
Часто требуется визуальная стрелка, указывающая на reference.
import { arrow } from '@floating-ui/dom';
const arrowEl = document.querySelector('.arrow');
computePosition(referenceEl, floatingEl, {
middleware: [
arrow({ element: arrowEl }),
],
});
Результат содержит координаты стрелки:
.then(({ middlewareData }) => {
const { x, y } = middlewareData.arrow;
Object.assign(arrowEl.style, {
left: x != null ? `${x}px` : '',
top: y != null ? `${y}px` : '',
});
});
Особенность:
Используется для inline-элементов (например, текстовых ссылок, разбитых на несколько строк).
import { inline } from '@floating-ui/dom';
inline()
Решает проблему:
При прокрутке, ресайзе или изменении DOM необходимо пересчитывать позицию.
import { autoUpdate } from '@floating-ui/dom';
const cleanup = autoUpdate(referenceEl, floatingEl, () => {
computePosition(referenceEl, floatingEl).then(...);
});
Отслеживает:
Остановка:
cleanup();
Floating UI может использовать CSS transform:
Object.assign(floatingEl.style, {
transform: `translate(${x}px, ${y}px)`,
});
Преимущества:
Floating UI корректно работает даже если:
Это достигается через:
Два режима:
strategy: 'absolute'
или
strategy: 'fixed'
absolute:
fixed:
Выбор:
absolutefixedFloating UI учитывает:
overflow: autooverflow: hiddenЭто важно, так как:
getBoundingClientRect могут
быть недостаточныPlacement автоматически адаптируется:
start и end меняются местамиdirection: rtlЭто избавляет от ручной логики.
Можно писать собственные middleware:
const customMiddleware = {
name: 'custom',
fn(state) {
return {
...state,
x: state.x + 10,
};
},
};
Подключение:
middleware: [customMiddleware]
1. Дёргание позиции Причина:
Решение:
2. Неправильное выравнивание Причина:
shiftplacement3. Выход за границы Причина:
flip или shiftFloating UI:
Это даёт:
Каждый этап влияет на финальные координаты, формируя адаптивную систему позиционирования, устойчивую к изменениям интерфейса и окружения.