Floating UI предоставляет мощный механизм для управления позиционированием всплывающих элементов, таких как тултипы, модальные окна и dropdown-меню. Важным компонентом этой системы являются middleware — функции, которые позволяют изменять поведение позиционирования и динамически модифицировать стили элементов.
Middleware вызываются на каждом кадре при обновлении позиции элемента и могут:
Middleware в Floating UI подключаются через массив
middleware, передаваемый в функцию
computePosition. Пример базовой структуры:
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
const referenceElement = document.querySelector('#button');
const floatingElement = document.querySelector('#tooltip');
computePosition(referenceElement, floatingElement, {
placement: 'top',
middleware: [
offset(10),
flip(),
shift({ padding: 5 })
]
}).then(({ x, y }) => {
Object.assign(floatingElement.style, {
left: `${x}px`,
top: `${y}px`
});
});
Middleware можно комбинировать в любом порядке, что дает гибкость при динамическом позиционировании.
Одной из ключевых возможностей Floating UI является использование
middleware для динамической модификации стилей, а не
только координат. Для этого middleware могут возвращать объект
data, который будет доступен на следующих шагах и может
использоваться для вычисления свойств CSS:
import { arrow } from '@floating-ui/dom';
const arrowElement = document.querySelector('#arrow');
computePosition(referenceElement, floatingElement, {
placement: 'top',
middleware: [
offset(10),
flip(),
shift({ padding: 5 }),
arrow({ element: arrowElement })
]
}).then(({ x, y, middlewareData }) => {
const { x: arrowX, y: arrowY } = middlewareData.arrow;
Object.assign(floatingElement.style, {
left: `${x}px`,
top: `${y}px`
});
Object.assign(arrowElement.style, {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : ''
});
});
Middleware arrow динамически вычисляет координаты
стрелки относительно всплывающего элемента, учитывая изменения позиции и
возможные перевороты. Таким образом, стили элемента становятся
полностью реактивными к изменениям позиции.
Floating UI позволяет создавать собственные middleware, возвращающие не только координаты, но и дополнительные данные для стилизации:
function dynamicBackground(options) {
return {
name: 'dynamicBackground',
fn({ placement, rects }) {
const background = rects.reference.width > 100 ? 'lightblue' : 'lightcoral';
return { data: { background } };
}
};
}
computePosition(referenceElement, floatingElement, {
middleware: [dynamicBackground()]
}).then(({ middlewareData }) => {
floatingElement.style.backgroundColor = middlewareData.dynamicBackground.background;
});
В данном примере middleware dynamicBackground вычисляет
цвет фона в зависимости от ширины элемента-источника. Это демонстрирует,
как middleware может использоваться не только для позиционирования, но и
для динамических стилей на основе состояния
интерфейса.
Для обеспечения плавного и динамического поведения рекомендуется
использовать autoUpdate:
import { autoUpdate } from '@floating-ui/dom';
autoUpdate(referenceElement, floatingElement, () => {
computePosition(referenceElement, floatingElement, {
placement: 'top',
middleware: [
offset(10),
flip(),
shift({ padding: 5 }),
arrow({ element: arrowElement }),
dynamicBackground()
]
}).then(({ x, y, middlewareData }) => {
Object.assign(floatingElement.style, {
left: `${x}px`,
top: `${y}px`,
backgroundColor: middlewareData.dynamicBackground.background
});
Object.assign(arrowElement.style, {
left: middlewareData.arrow.x != null ? `${middlewareData.arrow.x}px` : '',
top: middlewareData.arrow.y != null ? `${middlewareData.arrow.y}px` : ''
});
});
});
autoUpdate следит за изменением размеров, прокруткой и
движением элементов, автоматически пересчитывая позицию и обновляя
стили.
middlewareData для
передачи информации между middleware, чтобы избежать повторных
вычислений.transform: translate
вместо прямой установки top и left.Middleware в Floating UI превращают позиционирование из статического процесса в динамическую, реактивную систему, позволяющую управлять не только координатами, но и стилями элементов, адаптируя интерфейс под любые условия окна и содержимого.