Приоритеты при конфликтах пространства

Popper.js — это мощная библиотека для управления всплывающими элементами и их позиционированием относительно других элементов. Одной из ключевых задач при работе с Popper является разрешение конфликтов пространства: когда элемент не помещается в отведённую область, необходимо определить приоритеты смещения и поведение «поппера».

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

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

  • Boundaries — границы, в пределах которых должен оставаться поппер. Обычно это viewport или ближайший контейнер с overflow.
  • Fallbacks — альтернативные позиции, которые библиотека использует, если основная позиция недоступна.
  • Priority — порядок, в котором проверяются альтернативные позиции.

Модификатор flip

Модификатор flip отвечает за смену позиции поппера, если выбранная изначально позиция недоступна. Основные параметры:

  • behavior — массив возможных направлений, например ['top', 'right', 'bottom', 'left']. Поппер проверяет их по очереди и выбирает первую подходящую.
  • fallbackPlacements — расширение массива behavior, позволяющее определить дополнительные позиции для проверки.
  • padding — отступ от границ контейнера, который учитывается при проверке доступного пространства.
  • boundary — элемент или область, внутри которой поппер должен оставаться.

Пример конфигурации flip:

const popperInstance = Popper.createPopper(reference, popper, {
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['right', 'left'],
        padding: 8,
        boundary: 'viewport',
      },
    },
  ],
});

В этом примере при нехватке пространства сверху поппер попробует разместиться справа, затем слева, не выходя за границы viewport.

Модификатор preventOverflow

Этот модификатор предотвращает выход поппера за пределы контейнера. Основные параметры:

  • mainAxis — активирует контроль по основной оси (например, вертикальной для top/bottom).
  • altAxis — контроль по альтернативной оси (например, горизонтальной для top/bottom).
  • tether — если true, поппер «прилизывает» к границе, не позволяя полностью выйти за пределы.
  • padding — отступ от границ контейнера.
{
  name: 'preventOverflow',
  options: {
    mainAxis: true,
    altAxis: true,
    tether: true,
    padding: 10,
  },
}

Использование preventOverflow совместно с flip позволяет создавать гибкие сценарии позиционирования, в которых поппер сначала пытается разместиться по заданной позиции, а затем смещается внутрь видимой области.

Установка приоритетов

При конфликте пространства Popper.js учитывает порядок модификаторов и их настройки. Очередность выполнения имеет значение:

  1. computeStyles — определяет стиль и размеры поппера.
  2. flip — проверяет возможность смены позиции.
  3. preventOverflow — корректирует позицию для соблюдения границ.
  4. offset — смещает элемент дополнительно, если это необходимо.

Важно понимать, что порядок в массиве modifiers влияет на итоговое позиционирование. Например, если preventOverflow идёт перед flip, элемент может быть «зажат» внутри границ, и flip не сработает должным образом.

Настройка fallback-стратегий

Popper.js позволяет задавать кастомные fallback-стратегии через функцию fallbackPlacements или flip.behavior:

{
  name: 'flip',
  options: {
    beh * avior: (originalPlacement, availablePlacements, popperRect, referenceRect, boundaries) => {
      if (referenceRect.top < 100) {
        return ['bottom', 'right'];
      }
      return ['top', 'left'];
    },
  },
}

В этом примере поведение зависит от расположения референта: если расстояние до верхней границы меньше 100px, приоритет будет у bottom, иначе у top. Это даёт полный контроль над стратегией при конфликте пространства.

Сложные сценарии

  1. Динамическая высота поппера Если высота элемента неизвестна заранее, рекомендуется использовать preventOverflow с altAxis: true, чтобы избежать горизонтальных и вертикальных смещений за пределы контейнера.

  2. Множественные ограничения Можно задать несколько границ через boundary:

    boundary: ['viewport', 'scrollParent']

    Поппер сначала проверяет viewport, затем ближайший scrollParent, выбирая оптимальное расположение.

  3. Комбинация offset и flip Для тонкой настройки позиции часто используют offset после flip:

    {
      name: 'offset',
      options: {
        offset: [0, 12], // сдвиг по основной и альтернативной оси
      },
    }

    Это позволяет сохранять визуальный отступ, даже если позиция поппера была изменена модификатором flip.

Выводы по приоритетам

  • Поведение зависит от порядка модификаторов: flip и preventOverflow должны быть правильно расставлены.
  • Настройка fallback-стратегий позволяет полностью контролировать реакцию на нехватку пространства.
  • Комбинированное использование offset, tether, padding и boundary создаёт гибкую систему позиционирования, способную адаптироваться к любым изменениям размеров и положения референта.

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