Стилизация и отображение

В библиотеке Floating UI ключевым понятием является плавающий элемент (floating element) — элемент интерфейса, который позиционируется относительно другого элемента (reference element) с учётом доступного пространства на экране. Библиотека обеспечивает точное позиционирование с минимальным вмешательством разработчика, учитывая переполнение контейнеров, размеры окна и динамические изменения DOM.

Reference element — это элемент, относительно которого позиционируется плавающий блок. Floating element — это сам блок, который может быть тултипом, выпадающим меню, поповером или модальным элементом.

Floating UI не просто задаёт координаты top и left. Она предоставляет полноценную систему модификаторов, которые можно комбинировать для тонкой настройки поведения и стилей элементов.


Позиционирование и модификаторы

Позиционирование строится на функции computePosition(reference, floating, options). Основные параметры options:

  • placement — указывает начальное положение плавающего элемента относительно reference: top, bottom, left, right и их вариации с -start и -end.
  • strategy — выбирает стратегию позиционирования: absolute или fixed. absolute позволяет элементу следовать за прокруткой родителя, fixed делает элемент неподвижным относительно окна.
  • middleware — массив функций, которые изменяют вычисленные координаты или применяют дополнительные эффекты (смещение, ограничение по экрану, автоматическое смещение).

Пример базового позиционирования с middleware:

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

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

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

Выделенные моменты:

  • offset(10) — задаёт смещение на 10px от reference.
  • flip() — автоматически меняет сторону, если нет места.
  • shift({ padding: 5 }) — предотвращает выход элемента за границы viewport.

Стилизация плавающих элементов

Floating UI не управляет стилями напрямую, но позволяет точно позиционировать элементы, что облегчает работу с CSS. Для красивой интеграции стоит использовать:

  • CSS-переменные для динамических значений (например, смещения или стрелки тултипа).
  • transition и transform для анимаций появления и исчезновения.
  • z-index для контроля перекрытия элементов.

Пример стилизации тултипа с учётом вычисленных координат:

#tooltip {
  position: absolute;
  background-color: #333;
  color: #fff;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 14px;
  transition: opacity 0.2s ease, transform 0.2s ease;
  opacity: 0;
  pointer-events: none;
}

#tooltip.show {
  opacity: 1;
  pointer-events: auto;
}

С помощью JavaScript можно добавлять класс .show после вычисления позиции и обеспечить плавное появление.


Работа со стрелками и указателями

Для создания стрелки используется middleware arrow. Она позволяет точно позиционировать указатель относительно reference. Важные моменты:

  • arrow({ element }) — middleware для стрелки, где element — DOM-элемент стрелки.
  • padding — минимальное расстояние между стрелкой и границами floating element.
  • Расчёт координат стрелки возвращается в объекте middlewareData.arrow.

Пример:

import { arrow } from '@floating-ui/dom';

const arrowElement = document.querySelector('#tooltip-arrow');

computePosition(reference, floating, {
  placement: 'top',
  middleware: [offset(10), flip(), 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}px`, top: `${arrowY}px` });
});

Динамическое обновление позиции

Floating UI предоставляет autoUpdate для динамического отслеживания изменений положения reference или размеров окна. Она автоматически пересчитывает координаты без ручного вызова computePosition при каждом событии.

Пример:

import { autoUpdate } from '@floating-ui/dom';

const cleanup = autoUpdate(reference, floating, () => {
  computePosition(reference, floating, {
    placement: 'top',
    middleware: [offset(10), flip(), shift({ padding: 5 })],
  }).then(({ x, y }) => {
    Object.assign(floating.style, { left: `${x}px`, top: `${y}px` });
  });
});

// Для остановки обновлений
cleanup();

Комбинирование анимаций и видимости

Для более сложной стилизации используют CSS-анимации с transform на основе координат, вычисленных библиотекой. Обычно применяется комбинация:

  • opacity для плавного появления
  • translate3d(x, y, 0) для корректного рендеринга на GPU и предотвращения смазывания
  • transition для контроля скорости анимации

Пример анимации с учётом координат:

computePosition(reference, floating, { placement: 'bottom', middleware: [offset(8)] })
  .then(({ x, y }) => {
    floating.style.transform = `translate3d(${x}px, ${y}px, 0)`;
    floating.style.opacity = '1';
  });

Советы по стилизации

  • Использовать transform вместо top/left для плавных анимаций.
  • Минимизировать пересчёты layout: размещение через computePosition следует выполнять по событию, а не на каждом кадре.
  • Комбинировать middleware: offset, flip, shift и arrow позволяют создавать адаптивные интерфейсы.
  • Контролировать z-index: floating элемент должен иметь контекст над другими слоями интерфейса.
  • CSS-переменные для стрелки и паддингов упрощают изменение внешнего вида без изменения JavaScript-кода.

Эта система обеспечивает гибкое позиционирование и красивую визуальную интеграцию элементов интерфейса с минимальной нагрузкой на производительность.