Скрытие при выходе за границы

В библиотеке Floating UI управление видимостью всплывающих элементов при выходе за пределы контейнера осуществляется с помощью middleware hide. Этот middleware позволяет автоматически скрывать floating-элемент, если он оказывается за пределами видимой области или выходит за рамки определённого ограничения.

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

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

computePosition(reference, floating, {
  middleware: [offset(8), flip(), shift({ padding: 5 }), hide()]
}).then(({ x, y, middlewareData }) => {
  Object.assign(floating.style, {
    left: `${x}px`,
    top: `${y}px`,
    visibility: middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'
  });
});

В этом примере hide() проверяет два основных состояния:

  • referenceHidden – ссылка (элемент-источник) полностью вышла за пределы контейнера или viewport.
  • escaped – floating-элемент частично или полностью вышел за границы заданного ограничения.

Значения этих флагов можно использовать для динамического управления стилями и поведением всплывающего элемента.

Настройка границ скрытия

Middleware hide поддерживает параметр boundary, который задаёт область, относительно которой происходит проверка выхода. Это может быть:

  • viewport – стандартная область видимости браузера.
  • document.body – проверка относительно всей страницы.
  • Любой кастомный элемент DOM, который используется в качестве ограничения.
hide({ boundary: document.querySelector('#container') })

Параметр strategy определяет, как рассчитываются границы:

  • absolute – расчёт относительно документа.
  • fixed – расчёт относительно viewport.

Использование strategy полезно при работе с позиционированными контейнерами или модальными окнами.

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

Скрытие при выходе за границы часто комбинируется с flip и shift, чтобы floating-элемент корректно reposition-ился перед тем, как исчезнуть.

  • flip() меняет сторону отображения, если элемент выходит за границы.
  • shift() смещает элемент внутрь видимой области.
  • hide() реагирует на крайний случай, когда reposition невозможен.
middleware: [
  offset(10),
  flip(),
  shift({ padding: 8 }),
  hide({ boundary: document.body })
]

В такой цепочке hide срабатывает только после всех попыток корректного позиционирования.

Использование с динамическими событиями

Скрытие можно синхронизировать с событиями, например, при скролле или ресайзе окна. Для этого достаточно повторно вызывать computePosition и обновлять свойство visibility:

window.addEventListener('scroll', updatePosition);
window.addEventListener('resize', updatePosition);

function updatePosition() {
  computePosition(reference, floating, { middleware: [offset(8), flip(), hide()] })
    .then(({ x, y, middlewareData }) => {
      Object.assign(floating.style, {
        left: `${x}px`,
        top: `${y}px`,
        visibility: middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'
      });
    });
}

Такое решение позволяет поддерживать актуальное состояние видимости независимо от движения элементов на странице.

Практические советы

  • Использовать hide всегда вместе с flip и shift, чтобы минимизировать внезапное исчезновение элементов.
  • Проверять middlewareData.hide перед изменением visibility, чтобы избежать лишних перерисовок.
  • Для модальных или портальных элементов boundary лучше указывать родительский контейнер, чтобы ограничить область проверки.
  • В сложных интерфейсах можно комбинировать несколько hide с разными boundary для точного контроля поведения.

hide обеспечивает автоматическую реакцию на ограничение видимости, делая интерфейс гибким и предотвращая случайное “вылетание” всплывающих элементов за пределы экрана или контейнера.