В библиотеке Floating UI позиционирование элементов
относительно inline-элементов требует понимания того, как браузер
формирует контекст для inline-контента. Inline-элементы, такие как
<span>, <a> или
<strong>, занимают только ту область, которая
необходима для их контента, и не создают блочного контейнера. Это
означает, что для вычисления позиции всплывающих элементов (tooltip,
dropdown, popover) важно учитывать точные границы и координаты
inline-элемента.
Floating UI предоставляет несколько функций для вычисления позиции:
x и
y для плавающего элемента.Для inline-элементов особенно важно использовать rect-based reference, так как их размеры динамичны и зависят от текста, стилей и шрифтов.
Пример использования:
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
const reference = document.querySelector('span.reference');
const floating = document.querySelector('div.tooltip');
computePosition(reference, floating, {
middleware: [
offset(8), // отступ 8px
flip(), // изменение позиции при недостатке места
shift({ padding: 5 }) // корректировка по границам окна
]
}).then(({ x, y }) => {
Object.assign(floating.style, {
left: `${x}px`,
top: `${y}px`
});
});
Bounding Client Rect Inline-элементы имеют
нестандартные размеры: getBoundingClientRect() возвращает
размеры всего текста в элементе, включая возможные переносы строк. Для
многострочного inline-элемента координаты верхнего левого угла и нижнего
правого угла могут меняться динамически при изменении контента.
Baseline и vertical alignment Floating UI может
учитывать вертикальное выравнивание inline-элемента
(baseline, top, middle,
bottom). Важно использовать middleware shift
для корректировки позиции по вертикали, особенно если всплывающее окно
должно быть выровнено с текстом, а не с границами блока.
Проблемы с line-height и padding Line-height у
inline-элементов может добавлять пространство сверху и снизу текста, что
влияет на точку reference. В таких случаях middleware
offset помогает корректировать позицию, смещая плавающий
элемент на требуемое количество пикселей.
Если inline-элемент разбит на несколько текстовых узлов или требуется позиционирование относительно части текста, Floating UI позволяет использовать virtual elements:
const virtualReference = {
getBoundingClientRect() {
const range = document.createRange();
range.setStart(reference.firstChild, 0);
range.setEnd(reference.firstChild, 4); // первые 4 символа
return range.getBoundingClientRect();
}
};
computePosition(virtualReference, floating, {
middleware: [offset(4), flip(), shift({ padding: 5 })]
});
Такой подход позволяет точно привязать всплывающее окно к подстрочному тексту, а не ко всему inline-элементу целиком.
Пример использования arrow middleware с inline-элементом:
import { arrow } from '@floating-ui/dom';
const arrowElement = document.querySelector('.tooltip-arrow');
computePosition(reference, floating, {
middleware: [
offset(10),
flip(),
shift({ padding: 5 }),
arrow({ element: arrowElement })
]
}).then(({ x, y, middlewareData }) => {
Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
const { x: arrowX, y: arrowY } = middlewareData.arrow;
Object.assign(arrowElement.style, {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : ''
});
});
Для многострочных <span> или
<a> важно учитывать, что каждая строка может иметь
свои координаты. В таких случаях использование range-based
virtual elements обеспечивает точное позиционирование по первой
или последней строке текста, что критично для подсказок, появляющихся
рядом с конкретным словом.
getBoundingClientRect() inline-элемента
перед вычислением позиции.flip и shift для
предотвращения выхода всплывающего элемента за границы окна.Range.offset.Понимание этих особенностей позволяет Floating UI корректно и предсказуемо позиционировать элементы в сложных inline-контекстах, делая интерфейсы более точными и удобными для пользователя.