Родительские элементы как boundary

В Popper.js boundary — это ограничение, которое предотвращает выход всплывающего элемента за пределы заданной области. Часто требуется, чтобы поппер не выходил за видимую часть страницы или контейнер, в котором он расположен. Одним из наиболее распространённых способов задания границ является использование родительских элементов в качестве boundary.


Основные концепции

Popper.js управляет положением всплывающих элементов относительно их reference element (элемент-отправитель), автоматически подстраивая их позицию при изменении окна браузера или прокрутке страницы. Для контроля видимости используются модификаторы, один из которых — preventOverflow. Именно через него задаются границы.

  • boundary — параметр модификатора preventOverflow. Он может принимать:

    • 'viewport' — границы окна браузера,
    • 'scrollParent' — ближайший прокручиваемый родительский элемент,
    • DOM-элемент — конкретный контейнер,
    • массив DOM-элементов — несколько ограничений одновременно.

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

Для установки родителя как boundary необходимо:

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

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

createPopper(reference, popper, {
  modifiers: [
    {
      name: 'preventOverflow',
      options: {
        boundary: reference.parentElement, // родительский элемент reference
        padding: 8,                        // отступ от границы
      },
    },
  ],
});

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

  1. reference.parentElement — это прямой родитель элемента reference.
  2. padding предотвращает прилипание поппера к границе.
  3. Если parent имеет overflow: hidden, scroll или auto, Popper будет учитывать эти свойства при расчёте позиции.

Множественные границы

Иногда требуется учитывать несколько родительских элементов:

const boundaries = [
  reference.parentElement,
  document.querySelector('#main-container')
];

createPopper(reference, popper, {
  modifiers: [
    {
      name: 'preventOverflow',
      options: { boundary: boundaries },
    },
  ],
});

Popper будет стараться удерживать элемент внутри всех указанных контейнеров одновременно. Это особенно полезно при вложенных scrollable контейнерах.


Влияние CSS свойств родителя

При использовании родительских элементов как boundary важно учитывать их CSS:

  • position: relative | absolute | fixed — влияет на расчет offset для поппера.
  • overflow: hidden | scroll | auto — ограничивает видимую область popper.
  • transform на родителях создаёт containing block, что меняет систему координат для вычисления позиции.

Пример: если родитель имеет transform: translate(0,0), popper будет вычисляться относительно этого родителя, а не документа.


Работа с динамическим DOM

Если родительский элемент изменяется динамически (например, через JavaScript добавляется новый контейнер), boundary следует обновлять:

popper.setOptions({
  modifiers: [
    {
      name: 'preventOverflow',
      options: { boundary: newParent }
    }
  ]
});
popper.update();

Это позволяет поддерживать корректное позиционирование после изменений DOM.


Настройка смещения внутри boundary

Popper.js позволяет комбинировать boundary и offset для точной подгонки позиции:

createPopper(reference, popper, {
  modifiers: [
    {
      name: 'preventOverflow',
      options: { boundary: reference.parentElement }
    },
    {
      name: 'offset',
      options: { offset: [0, 12] } // смещение по оси Y на 12px
    }
  ]
});

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


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

  • Для обычных всплывающих подсказок в интерфейсе часто используют scrollParent или прямой родитель, чтобы избежать выхода за пределы контейнера.
  • Для модальных окон или диалогов лучше использовать viewport как boundary, чтобы учитывать видимую область экрана.
  • Всегда проверять свойства CSS родительских элементов, особенно overflow и transform, так как они напрямую влияют на расчёт позиции.

Использование родительских элементов как boundary в Popper.js обеспечивает гибкий и безопасный способ контроля видимости всплывающих элементов внутри интерфейса, предотвращая их выход за пределы контейнеров и сохраняя удобство для пользователей.