Сдвиг вдоль оси размещения

Библиотека Floating UI предоставляет мощные инструменты для динамического позиционирования элементов в веб-приложениях. Одним из ключевых аспектов управления положением плавающих элементов является сдвиг вдоль оси размещения, который позволяет точнее контролировать позицию всплывающих элементов относительно их исходного якоря.


Основное понятие mainAxis и crossAxis

Floating UI использует концепцию осей для управления положением элемента:

  • Main Axis (основная ось) – направление, по которому элемент «выпадает» относительно якоря. Например, для всплывающего меню, расположенного справа от кнопки, основной осью является горизонтальная ось X.
  • Cross Axis (поперечная ось) – перпендикулярное направление, которое используется для корректировки смещения по другой координате, обеспечивая выравнивание и предотвращение перекрытий.

Сдвиг вдоль mainAxis реализуется через модуль offset, который принимает числовое значение или функцию, возвращающую смещение в пикселях. Это позволяет гибко настраивать положение всплывающего элемента.


Использование модификатора offset

Базовый пример применения:

import { computePosition, offset } from '@floating-ui/dom';

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

computePosition(reference, floating, {
  middleware: [
    offset({ mainAxis: 10 })
  ],
}).then(({ x, y }) => {
  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`,
  });
});

В данном примере:

  • mainAxis: 10 — сдвигает элемент на 10 пикселей в направлении основной оси.
  • При изменении mainAxis смещение автоматически учитывается при вычислении позиции элемента относительно якоря.

Важно: если элемент размещается сверху (top) или снизу (bottom) от якоря, основная ось будет вертикальной, а для left или right — горизонтальной. Это напрямую влияет на направление сдвига.


Функциональный подход к сдвигу

Для динамических интерфейсов удобно использовать функцию вместо фиксированного числа:

offset({
  mainAxis: ({ rects, placement }) => {
    if (placement.startsWith('top')) return 5;
    if (placement.startsWith('bottom')) return 15;
    return 10;
  }
});

Здесь функция получает объект с параметрами:

  • rects.reference – размеры и положение якоря.
  • rects.floating – размеры плавающего элемента.
  • placement – текущая позиция (top, bottom, left, right).

Это позволяет изменять смещение в зависимости от контекста и размера элементов.


Сдвиг по поперечной оси (crossAxis)

Сдвиг вдоль crossAxis особенно полезен для корректировки выравнивания, когда основной элемент не центрирован или требуется дополнительный отступ:

offset({
  mainAxis: 10,
  crossAxis: 20
});
  • crossAxis: 20 — сдвигает элемент перпендикулярно основной оси на 20 пикселей.
  • Может применяться вместе с mainAxis для точного позиционирования, например, для всплывающих подсказок или меню, чтобы избежать наложения на другие элементы интерфейса.

Комбинирование offset с другими middleware

Floating UI позволяет комбинировать offset с flip, shift, autoPlacement:

computePosition(reference, floating, {
  middleware: [
    offset({ mainAxis: 12, crossAxis: 8 }),
    flip(),
    shift({ padding: 5 })
  ],
});
  • flip() — переворачивает элемент, если он выходит за границы контейнера.
  • shift() — корректирует положение, чтобы элемент не выходил за видимую область.
  • offset() выполняется первым и задаёт базовый сдвиг по осям, после чего flip и shift корректируют положение.

Правильная комбинация позволяет достичь естественного и предсказуемого позиционирования, особенно в сложных интерфейсах.


Рекомендации по использованию mainAxis и crossAxis

  • Сдвиг вдоль основной оси стоит использовать для создания визуального отступа от якоря, чтобы элемент не «слипался» с кнопкой или ссылкой.
  • Сдвиг по поперечной оси удобен для адаптивной верстки: он компенсирует различия размеров элементов, предотвращает наложение на соседние компоненты.
  • Для динамических интерфейсов лучше использовать функции вместо фиксированных чисел, учитывая размеры элементов и направление размещения.