Floating UI в JavaScript предоставляет гибкий инструмент для управления позиционированием элементов поверх основного контента. Когда речь идёт о вложенных Floating элементах, важно понимать иерархию контекста и цепочку зависимостей позиции. Каждый Floating элемент может быть как независимым, так и зависимым от родительского Floating элемента.
Принцип работы:
absolute, fixed) и
срабатывает на события взаимодействия с пользователем или обновления
родителя.Absolute Используется, когда дочерний элемент
должен располагаться относительно ближайшего позиционированного
родителя. В контексте Floating UI это чаще всего
reference element родительского Floating.
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
const parent = document.querySelector('#parent');
const child = document.querySelector('#child');
computePosition(parent, child, {
placement: 'bottom-start',
middleware: [offset(5), flip(), shift({ padding: 8 })],
}).then(({ x, y }) => {
Object.assign(child.style, {
left: `${x}px`,
top: `${y}px`,
position: 'absolute',
});
});Fixed Используется, когда элемент должен
игнорировать скроллинг родителя. Вложенные Floating элементы с
fixed позиционированием не наследуют
смещения родителя.
Выбор стратегии зависит от поведения интерфейса:
если дочерний элемент является частью выпадающего меню, лучше
использовать absolute. Если это отдельный контекст, который
должен оставаться на экране при скролле, применяют
fixed.
1. Offset Позволяет смещать дочерний элемент относительно родителя. При вложенности смещение может быть кумулятивным.
2. Flip Позволяет дочернему Floating элементу менять сторону, если родитель выходит за границы viewport. Важно учитывать, что Flip дочернего элемента срабатывает после вычисления позиции родителя.
3. Shift Сдвигает элемент внутрь видимой области. Вложенные элементы получают значения с учётом родителя, что предотвращает наложение за пределами экрана.
4. Arrow Для вложенных элементов стрелка должна
учитывать родительский элемент, иначе визуальная связь нарушается.
Floating UI позволяет вычислять arrow позицию независимо
для каждого уровня.
Вложенные Floating элементы часто требуют динамического обновления позиции при изменении размера или скролла родителя:
import { autoUpdate } from '@floating-ui/dom';
autoUpdate(parent, child, () => {
computePosition(parent, child, {
placement: 'bottom-start',
middleware: [offset(5), flip(), shift()],
}).then(({ x, y }) => {
Object.assign(child.style, {
left: `${x}px`,
top: `${y}px`,
});
});
});
autoUpdate автоматически отслеживает скролл, ресайз
окна и изменения размеров элементов.autoUpdate для
каждого уровня иерархии, иначе позиция дочернего элемента может
сбиваться при движении родителя.Выпадающие меню с подменю Родительское меню управляет положением верхнего уровня, подменю рассчитывает позицию относительно активного пункта:
bottom-startright-start с middleware flip()
и shift()Tooltip внутри модального окна Tooltip позиционируется относительно кнопки внутри модального. Вложенность помогает учитывать смещения модального и viewport.
Комбинированные контекстные панели Панели,
которые открываются друг над другом, используют absolute
позиционирование и middleware offset + flip.
Важно правильно передавать reference element дочернего
уровня.
autoUpdate только для видимых элементов,
чтобы снизить нагрузку при множестве вложенных Floating.flip и shift, так как они требуют сложных
вычислений.Вложенные Floating элементы требуют правильного управления слоёвостью:
transform, дочерний
absolute элемент будет позиционироваться относительно
transformed ancestor, что важно учитывать при сложных интерфейсах.Для компонентов React и Vue Floating UI предоставляет хуки:
useFloating — основной хук для позиции.useInteractions — позволяет связывать клики, hover и
фокус с отображением вложенных элементов.Пример для React:
import { useFloating, offset, flip, shift } from '@floating-ui/react';
const { x, y, reference, floating } = useFloating({
placement: 'bottom-start',
middleware: [offset(5), flip(), shift()],
});
Дочерние элементы используют собственный useFloating с
reference на родительский элемент, что создаёт
иерархическую цепочку для правильного
позиционирования.
offset, flip,
shift, arrow применяются отдельно на каждом
уровне.absolute или
fixed) определяет зависимость от родителя и поведение при
скролле.autoUpdate) необходимо для
динамических интерфейсов, но следует оптимизировать для
производительности.Всё это позволяет создавать сложные интерфейсы с несколькими уровнями Floating элементов без нарушения UX и корректно обрабатывать динамические изменения DOM и viewport.