Floating UI предоставляет механизмы для динамического позиционирования элементов интерфейса, таких как тултипы, поповеры, контекстные меню. Ключевой аспект — поддержание актуальной позиции плавающего элемента при изменениях DOM, размера или позиции целевого элемента. Для этого используются стратегии реактивного обновления и наблюдения за изменениями DOM.
autoUpdate
— автоматическое обновление позицииМетод autoUpdate позволяет Floating UI автоматически
отслеживать изменения размера или положения элементов. Он принимает
четыре аргумента:
import { autoUpdate, computePosition } from '@floating-ui/dom';
const cleanup = autoUpdate(referenceElement, floatingElement, () => {
computePosition(referenceElement, floatingElement, {
placement: 'bottom',
}).then(({ x, y }) => {
Object.assign(floatingElement.style, {
left: `${x}px`,
top: `${y}px`,
});
});
});
Ключевые моменты:
referenceElement — элемент, относительно которого
позиционируется плавающий элемент.floatingElement — сам плавающий элемент.cleanup — функция для прекращения
наблюдения.autoUpdate объединяет три типа наблюдения:
Это делает autoUpdate универсальным решением для
реактивного позиционирования.
Иногда требуется отслеживать только определенные изменения DOM, чтобы избежать лишних вычислений позиции. Floating UI позволяет интегрировать кастомные наблюдатели:
const observer = new MutationObserver(() => {
computePosition(referenceElement, floatingElement, {
placement: 'top',
}).then(({ x, y }) => {
Object.assign(floatingElement.style, { left: `${x}px`, top: `${y}px` });
});
});
observer.observe(referenceElement, {
attributes: true, // следить за изменением атрибутов
childList: true, // следить за добавлением/удалением дочерних узлов
subtree: true, // включить всех потомков
});
Особенности:
computePosition только при нужных изменениях.observer.disconnect() останавливает наблюдение.referenceHidden и middleware для динамических
измененийFloating UI предоставляет middleware, которые реагируют на изменение DOM и видимости:
hide — автоматически определяет, когда
reference скрыт (например, display: none или вынос за пределы viewport)
и можно скрывать плавающий элемент.flip и
shift — корректируют позицию при изменении
размеров или положения reference.Пример с middleware:
import { computePosition, offset, flip, shift, hide } from '@floating-ui/dom';
computePosition(referenceElement, floatingElement, {
placement: 'bottom',
middleware: [offset(8), flip(), shift(), hide()],
}).then(({ x, y, middlewareData }) => {
Object.assign(floatingElement.style, { left: `${x}px`, top: `${y}px` });
if (middlewareData.hide?.referenceHidden) {
floatingElement.style.display = 'none';
} else {
floatingElement.style.display = 'block';
}
});
Особенности:
middlewareData.hide.referenceHidden сообщает, что
reference не виден.flip и shift обеспечивает
адаптивное позиционирование при изменениях DOM или
размеров контейнеров.При больших и сложных деревьях DOM важно минимизировать
количество вызовов computePosition:
let frame;
autoUpdate(referenceElement, floatingElement, () => {
if (frame) cancelAnimationFrame(frame);
frame = requestAnimationFrame(() => {
computePosition(referenceElement, floatingElement, { placement: 'top' })
.then(({ x, y }) => {
Object.assign(floatingElement.style, { left: `${x}px`, top: `${y}px` });
});
});
});
top/left для лучшей производительности при анимациях.Использование комбинации autoUpdate,
MutationObserver и middleware
обеспечивает:
Это делает Floating UI надежным инструментом для реактивного позиционирования в сложных веб-приложениях.