Получение координат стрелки

В библиотеке Floating UI стрелка — это визуальный элемент, указывающий на источник всплывающего элемента (popper, tooltip, dropdown). Правильное позиционирование стрелки требует знания точных координат относительно родительского элемента и контекста позиции. Floating UI предоставляет утилиту arrow для вычисления этих координат с учётом смещения и границ видимой области.

Импорт и подготовка к использованию

Для работы со стрелкой необходимо импортировать модуль arrow из @floating-ui/dom или @floating-ui/react (в зависимости от среды):

import { arrow, offset, flip, shift, computePosition } from '@floating-ui/dom';
  • arrow — вычисляет координаты стрелки.
  • offset — задаёт смещение всплывающего элемента от reference.
  • flip — обеспечивает автоматическое изменение стороны при нехватке места.
  • shift — корректирует позицию, чтобы элемент не выходил за границы viewport.
  • computePosition — центральная функция, возвращающая финальные координаты.

Настройка стрелки

Стрелка должна быть DOM-элементом внутри всплывающего блока. Обычно структура выглядит так:

<div id="tooltip">
  Tooltip content
  <div id="arrow" class="arrow"></div>
</div>

CSS для стрелки может использоваться следующий:

.arrow {
  width: 10px;
  height: 10px;
  background: black;
  transform: rotate(45deg);
  position: absolute;
}

Вычисление позиции стрелки

arrow работает через функцию computePosition, которая возвращает объект с координатами:

const reference = document.querySelector('#button');
const floating = document.querySelector('#tooltip');
const arrowEl = document.querySelector('#arrow');

computePosition(reference, floating, {
  middleware: [
    offset(8),
    flip(),
    shift({ padding: 5 }),
    arrow({ element: arrowEl })
  ],
}).then(({ x, y, middlewareData }) => {
  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`
  });

  const { x: arrowX, y: arrowY } = middlewareData.arrow;
  Object.assign(arrowEl.style, {
    left: arrowX != null ? `${arrowX}px` : '',
    top: arrowY != null ? `${arrowY}px` : ''
  });
});

Ключевые моменты:

  • middlewareData.arrow содержит координаты x и y, рассчитанные с учётом позиции reference.
  • Если стрелка позиционируется по горизонтали, x используется для сдвига стрелки, y оставляется пустым. Для вертикальной позиции наоборот.
  • offset задаёт расстояние между reference и всплывающим элементом, которое учитывается при вычислении стрелки.

Настройка смещения стрелки

Стрелку можно смещать относительно центра всплывающего элемента через опцию padding:

arrow({ element: arrowEl, padding: 5 })
  • padding ограничивает движение стрелки, чтобы она не пересекала края всплывающего блока.
  • Можно использовать динамическое вычисление, чтобы стрелка не выходила за видимую область при адаптивной верстке.

Обработка изменения позиции

Если всплывающий элемент может менять позицию (например, при скролле или ресайзе окна), координаты стрелки следует пересчитывать:

function updatePosition() {
  computePosition(reference, floating, {
    middleware: [offset(8), flip(), shift({ padding: 5 }), arrow({ element: arrowEl })]
  }).then(({ x, y, middlewareData }) => {
    Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
    const { x: arrowX, y: arrowY } = middlewareData.arrow;
    Object.assign(arrowEl.style, {
      left: arrowX != null ? `${arrowX}px` : '',
      top: arrowY != null ? `${arrowY}px` : ''
    });
  });
}

window.addEventListener('resize', updatePosition);
window.addEventListener('scroll', updatePosition, true);
  • true в addEventListener для scroll позволяет отслеживать прокрутку любого родителя, а не только окна.
  • Это гарантирует, что стрелка всегда указывает на правильное место reference.

Тонкости позиционирования

  1. Направление стрелки: вычисляется автоматически в зависимости от стороны (top, bottom, left, right) и выбранного middleware flip.
  2. Поддержка трансформаций: если родительский элемент имеет CSS transform, координаты стрелки будут корректными, так как Floating UI работает с bounding client rect.
  3. Динамическая адаптация: стрелка подстраивается под изменение размера окна и содержимого reference.

Расширенные возможности

  • Использование нескольких middleware позволяет гибко контролировать поведение стрелки: комбинирование offset, flip, shift и arrow даёт точное позиционирование и предотвращает выход стрелки за пределы блока.
  • Можно задавать минимальные и максимальные координаты стрелки для ограничения её движения по оси.
  • Поддерживается работа со scrollable контейнерами и элементами с position: relative или fixed.

В результате применение Floating UI и middleware arrow позволяет создавать всплывающие элементы с динамически корректируемой стрелкой, полностью учитывающей положение reference, границы viewport и пользовательские смещения.