Выбор reference и popper элементов

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


Элемент reference

reference может быть:

  • DOM-элементом:
  • Виртуальным элементом: объект с определёнными координатами, не привязанный к DOM. Используется, когда требуется позиционировать popper относительно кастомной точки, а не существующего элемента.

Ключевые требования к reference:

  • Элемент должен существовать в DOM на момент инициализации Popper.

  • Элемент не должен быть display: none — Popper.js не сможет корректно рассчитать размеры.

  • При использовании виртуального элемента необходимо определить свойства:

    const virtualReference = {
      getBoundingClientRect: () => ({
        width: 100,
        height: 50,
        top: 200,
        right: 300,
        bottom: 250,
        left: 200,
      }),
      contextElement: document.body, // элемент, используемый для вычисления boundaries
    };

Примечание: getBoundingClientRect должен возвращать объект с ключами top, left, bottom, right, width, height. Эти значения используются движком Popper для точного позиционирования.


Элемент popper

popper — это всплывающий элемент, который будет позиционироваться относительно reference. Он может быть:

  • Любым DOM-элементом с видимым содержимым.
  • Элементом с абсолютным или фиксированным позиционированием (position: absolute / fixed) для корректного взаимодействия с viewport и boundaries.

Рекомендации по выбору popper:

  • Элемент должен находиться в DOM, иначе Popper.js не сможет корректно его позиционировать.
  • Не рекомендуется использовать display: none или visibility: hidden. Если необходимо скрыть элемент, лучше применять opacity: 0 или transform: scale(0).
  • Если popper вложен в контейнер с overflow: hidden, следует использовать опцию strategy: 'fixed' для корректного отображения.

Передача элементов в Popper.js

Popper создаётся с помощью функции createPopper(reference, popper, options):

const referenceElement = document.querySelector('#button');
const popperElement = document.querySelector('#tooltip');

const popperInstance = Popper.createPopper(referenceElement, popperElement, {
  placement: 'top',
  strategy: 'absolute',
});
  • referenceElement — элемент, относительно которого позиционируется popper.
  • popperElement — сам всплывающий блок.
  • options — объект с настройками (placement, strategy, modifiers и др.).

Особенности передачи виртуальных элементов:

const virtualReference = {
  getBoundingClientRect: () => ({
    width: 50,
    height: 50,
    top: 100,
    left: 150,
    bottom: 150,
    right: 200,
  }),
};

const popperElement = document.querySelector('#tooltip');

Popper.createPopper(virtualReference, popperElement, {
  placement: 'right',
});

Управление boundaries и strategy

Popper.js использует reference и popper для расчёта:

  • Boundaries — область, в пределах которой popper может отображаться. Обычно это viewport или родительский контейнер.

  • Strategy — влияет на тип позиционирования popper:

    • absolute — относительно ближайшего позиционированного предка.
    • fixed — относительно viewport, игнорируя предков с overflow: hidden.

Выбор правильной комбинации reference, popper и strategy критичен при работе с элементами внутри scrollable контейнеров.


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

Если reference или popper создаются динамически (например, при рендере через JavaScript):

  • Инициализацию Popper следует производить после добавления элементов в DOM.
  • Для элементов, которые появляются по событию (hover, click), создаётся отдельный экземпляр Popper на момент отображения.
  • Можно использовать функцию update() для перерасчёта позиции после изменения размеров или позиции reference.
popperInstance.update();

Множественные reference элементы

Popper.js позволяет работать с несколькими reference через создание нескольких экземпляров. Каждый reference должен иметь отдельный popper. Использование одного popper для нескольких reference может привести к конфликтам в позиционировании.


Важные детали

  • reference не обязательно должен быть видимым на экране, но popper корректно отобразится только при наличии видимых координат.
  • При изменении размеров popper или reference рекомендуется использовать resizeObserver для автоматического обновления позиции.
  • Для работы с анимациями рекомендуется использовать modifiers типа flip и preventOverflow, чтобы popper оставался в пределах видимой области.