Root boundary

В Popper.js термин root boundary обозначает элемент, который ограничивает область, в которой всплывающий элемент (popper) может отображаться. Этот параметр напрямую влияет на вычисление позиции, предотвращение выхода за границы и срабатывание модификаторов, таких как preventOverflow.

По умолчанию Popper.js использует viewport как границу. Однако при работе с прокручиваемыми контейнерами или сложной структурой DOM часто требуется задать собственную границу.


Определение root boundary

Root boundary задаётся через опцию boundary внутри конфигурации Popper:

import { createPopper } from '@popperjs/core';

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

createPopper(reference, popper, {
  modifiers: [
    {
      name: 'preventOverflow',
      options: {
        boundary: document.querySelector('#container') // root boundary
      },
    },
  ],
});

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

  • boundary может принимать:

    • DOM-элемент (HTMLElement) – граница будет ограничена этим элементом.
    • clippingParents – Popper.js будет использовать ближайшие родительские элементы с обрезкой (overflow: hidden, scroll, auto) в качестве границ.
    • viewport – стандартная граница, окно браузера.
    • document – вся страница.
  • root boundary определяет не только визуальные границы, но и влияет на логику модификаторов, таких как flip, hide и preventOverflow.


Взаимодействие с модификатором preventOverflow

Модификатор preventOverflow предотвращает выход всплывающего элемента за границы. Использование кастомного root boundary позволяет контролировать, где Popper может перемещаться:

modifiers: [
  {
    name: 'preventOverflow',
    options: {
      boundary: document.querySelector('#scrollable-container'),
      padding: 8
    },
  },
]

Пояснения:

  • padding – добавляет внутреннее расстояние между Popper и границей.
  • Если граница ограничена контейнером с прокруткой, Popper автоматически адаптируется при прокрутке, оставаясь видимым внутри заданного элемента.

Отличие root boundary от fallback boundaries

  • Root boundary – основной элемент, используемый для расчета позиции и предотвращения выхода.
  • Fallback boundaries – дополнительные границы, которые Popper использует при необходимости смены позиции (например, срабатывает модификатор flip).
modifiers: [
  {
    name: 'flip',
    options: {
      fallbackPlacements: ['top', 'bottom'],
      boundary: document.querySelector('#container') // root boundary
    },
  },
]

Popper сначала проверяет root boundary, затем fallback placements, чтобы найти наилучшую видимую позицию.


Использование с прокручиваемыми контейнерами

Для элементов внутри скроллящихся контейнеров важно корректно задавать root boundary. В противном случае Popper может визуально «выпадать» за пределы видимой области контейнера.

const scrollContainer = document.querySelector('#scrollable-area');

createPopper(reference, popper, {
  modifiers: [
    {
      name: 'preventOverflow',
      options: {
        boundary: scrollContainer,
        tether: true // позволяет Popper оставаться «прицепленным» к reference
      },
    },
  ],
});

Особенности:

  • tether: true закрепляет Popper относительно reference даже при прокрутке.
  • Если root boundary меньше размера Popper, элемент может сжиматься или менять позицию.

Особенности при использовании transform и fixed

  • Если контейнер с root boundary имеет CSS-свойство transform, Popper корректно рассчитывает координаты внутри transformed space.
  • При использовании position: fixed root boundary всё равно учитывается, но координаты рассчитываются относительно viewport, а не обычного потока документа.

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

  • Для модальных окон и tooltips внутри ограниченных блоков всегда задавать root boundary равным контейнеру.
  • Использовать clippingParents, если структура DOM сложная и неизвестно заранее, какой элемент будет ограничивать Popper.
  • Комбинировать с padding для обеспечения визуального пространства между Popper и границей.
  • Проверять влияние CSS-свойств контейнера (overflow, transform) на расчёт позиции.

Визуальное поведение

  • Root boundary обеспечивает, чтобы Popper не выходил за видимую область родителя.
  • При изменении размеров контейнера Popper автоматически подстраивается, если активен preventOverflow.
  • Flip и hide реагируют на root boundary и корректно переключают позиции или скрывают элемент, если границы недостижимы.

Итог

Root boundary — ключевой инструмент Popper.js для управления видимостью и положением всплывающих элементов. Правильное определение root boundary обеспечивает стабильное поведение Popper в сложных и прокручиваемых интерфейсах, предотвращает визуальные артефакты и улучшает UX.