Floating UI — это современная библиотека для управления позиционированием плавающих элементов в веб-приложениях на JavaScript. Она особенно эффективна в создании сложных интерфейсов, где необходимо динамически размещать всплывающие окна, подсказки, dropdown’ы и другие интерактивные компоненты относительно других элементов страницы.
Основная идея Floating UI заключается в разделении двух задач:
Для сложных layouts важно учитывать:
flip, shift и offset.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(8), flip(), shift({ padding: 5 })]
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`
});
});
В этом примере комбинация middleware обеспечивает: отступ, автоматическую смену позиции при нехватке места и корректировку с учётом границ.
В сложных интерфейсах часто возникает ситуация, когда один floating элемент находится внутри другого. Например, dropdown внутри модального окна. В таких случаях важно:
computePosition
рекурсивно или autoUpdate, чтобы элементы
реагировали на изменения родителей.import { autoUpdate } from '@floating-ui/dom';
autoUpdate(reference, floating, () => {
computePosition(reference, floating, {
placement: 'right',
middleware: [offset(10), flip()]
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`
});
});
});
autoUpdate отслеживает изменения размеров и положения
родителя и автоматически пересчитывает координаты дочернего
элемента.
В сложных layouts нередко требуется, чтобы плавающие элементы
не выходили за пределы определенного контейнера, а не
всего viewport. Для этого Floating UI предоставляет middleware
limitShift и size:
shift — сдвигает элемент, чтобы он не
выходил за границы viewport.limitShift — ограничивает сдвиг
определёнными значениями.size — динамически подстраивает
размеры floating элемента под контейнер.computePosition(reference, floating, {
placement: 'bottom-start',
middleware: [
offset(5),
shift({ boundary: document.querySelector('#container') }),
size({ apply({ rects, availableHeight }) {
floating.style.height = `${availableHeight}px`;
}})
]
});
Такой подход позволяет создавать dropdown’ы и всплывающие окна, полностью адаптированные под сложные контейнерные структуры.
Для сложных интерфейсов middleware можно комбинировать, создавая цепочки трансформаций:
import { arrow } from '@floating-ui/dom';
computePosition(reference, floating, {
placement: 'top',
middleware: [
offset(10),
flip(),
shift({ padding: 5 }),
arrow({ element: floating.querySelector('.arrow') })
]
});
Комбинация middleware позволяет строить гибкие и надёжные плавающие компоненты даже в самых запутанных layouts.
Для интерфейсов с анимацией или динамическим контентом важно поддерживать актуальное позиционирование:
autoUpdate — наблюдает за изменениями
размеров и положения элементов.useFloating в React) для
автоматического обновления.import { useFloating } from '@floating-ui/react';
const { x, y, reference, floating } = useFloating({
placement: 'bottom',
middleware: [offset(8), flip(), shift({ padding: 5 })]
});
Использование реактивного подхода упрощает работу с динамическими интерфейсами, где содержимое элементов постоянно меняется.
Когда floating элемент рендерится в другом месте
DOM, необходимо корректно учитывать координаты viewport и
скролла. Floating UI поддерживает работу с порталами с помощью передачи
strategy: 'fixed' или
strategy: 'absolute':
absolute — позиционирование
относительно ближайшего позиционированного предка.fixed — позиционирование относительно
viewport, игнорируя скролл.computePosition(reference, floating, {
placement: 'bottom',
strategy: 'fixed',
middleware: [offset(5), flip()]
});
Выбор стратегии критичен для модальных окон, тултипов и сложных nested dropdown’ов.