Автоматическое переворачивание

Автоматическое переворачивание — один из ключевых механизмов позиционирования в Popper.js, обеспечивающий корректное отображение всплывающих элементов (tooltip, dropdown, popover) в условиях ограниченного пространства. Основная задача — предотвратить выход элемента за границы видимой области (viewport) или заданного контейнера.

Принцип работы

Изначально всплывающий элемент (popper) размещается относительно опорного элемента (reference) согласно заданному placement (например, top, bottom, left, right). Однако при нехватке пространства Popper.js анализирует доступные области и при необходимости изменяет сторону отображения.

Пример:

createPopper(referenceElement, popperElement, {
  placement: 'top'
});

Если сверху недостаточно места, библиотека автоматически попробует разместить элемент снизу (bottom), затем по бокам.

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

Автоматическое переворачивание реализовано через модификатор flip. Он включён по умолчанию и управляет логикой выбора альтернативных позиций.

Пример настройки:

createPopper(referenceElement, popperElement, {
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['bottom', 'right', 'left']
      }
    }
  ]
});

fallbackPlacements

Свойство fallbackPlacements определяет порядок альтернативных позиций, которые Popper.js будет проверять при нехватке места.

Принцип:

  1. Проверяется исходное положение (placement)
  2. Если не помещается — берётся первое значение из fallbackPlacements
  3. Проверка продолжается по списку

Если список не задан, Popper.js использует стандартную стратегию:

  • противоположная сторона (например, topbottom)
  • затем боковые варианты

Алгоритм выбора позиции

Процесс включает несколько этапов:

  1. Вычисление границ

    • Определяются размеры reference и popper
    • Вычисляется доступное пространство относительно границ (viewport, clippingParents, или пользовательского контейнера)
  2. Проверка переполнения (overflow)

    • Используется внутренний механизм detectOverflow
    • Определяется, выходит ли popper за пределы
  3. Сравнение доступных вариантов

    • Для каждого placement вычисляется степень переполнения
    • Выбирается вариант с минимальными нарушениями
  4. Применение лучшего варианта

boundary и rootBoundary

Контроль области, внутри которой работает flip:

{
  name: 'flip',
  options: {
    boundary: 'clippingParents',
    rootBoundary: 'viewport'
  }
}
  • boundary — контейнер, относительно которого проверяется переполнение
  • rootBoundary — глобальная граница (обычно viewport)

Возможные значения:

  • 'viewport'
  • 'document'
  • DOM-элемент

padding

Позволяет задать отступ от границы, чтобы popper не прилегал вплотную:

{
  name: 'flip',
  options: {
    padding: 8
  }
}

Это значение учитывается при расчёте доступного пространства.

altBoundary

По умолчанию переполнение рассчитывается относительно popper. Опция altBoundary переключает расчёт на reference-элемент:

{
  name: 'flip',
  options: {
    altBoundary: true
  }
}

Полезно при сложных вложенных контейнерах и прокрутке.

flipVariations

Если используется вариативное размещение (start, end), можно разрешить или запретить их изменение:

{
  name: 'flip',
  options: {
    flipVariations: true
  }
}

Пример:

  • top-start может превратиться в top-end, если это уменьшает переполнение

Ограничение количества проверок

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

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

preventOverflow

flip тесно связан с preventOverflow. Их различие:

  • flip — меняет сторону размещения
  • preventOverflow — сдвигает popper внутри текущей стороны

Пример совместного использования:

modifiers: [
  {
    name: 'flip',
    options: {
      fallbackPlacements: ['bottom', 'right']
    }
  },
  {
    name: 'preventOverflow',
    options: {
      padding: 8
    }
  }
]

offset

После переворачивания сохраняется логика смещения (offset), что может влиять на итоговую позицию.

Частые сценарии

Tooltip возле края экрана

  • Начальное положение: top
  • Недостаточно места сверху
  • Flip → bottom
  • boundary: контейнер
  • popper не выходит за пределы родителя
  • flip учитывает внутренние ограничения

Мобильные устройства

  • часто активируется flip из-за малого viewport
  • важно корректно задавать fallbackPlacements

Отладка

Для анализа поведения:

  • включение визуальных границ (через devtools)
  • логирование текущего placement:
instance.state.placement
  • проверка overflow через внутренние методы

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

  • явно задавать fallbackPlacements для предсказуемости
  • использовать padding, чтобы избежать «прилипания» к краям
  • комбинировать с preventOverflow, а не заменять
  • учитывать scroll-контейнеры через boundary
  • избегать чрезмерного количества fallback-позиций

Типичные ошибки

1. Игнорирование контейнеров прокрутки Popper может «обрезаться», если boundary задан некорректно.

2. Слишком длинный список fallbackPlacements Увеличивает вычисления без реальной пользы.

3. Отключение flip без альтернативы Приводит к выходу элемента за экран.

4. Неправильная работа с вариациями (start/end) Может вызывать неожиданные смещения.

Расширенная настройка

Пример комплексной конфигурации:

createPopper(reference, popper, {
  placement: 'top-start',
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['bottom-start', 'right-start'],
        padding: 10,
        boundary: document.body,
        rootBoundary: 'viewport',
        flipVariations: true
      }
    }
  ]
});

Внутренняя логика Popper.js

Flip использует данные из state.rects и state.modifiersData. Ключевые этапы:

  • сбор метрик
  • вычисление overflow для каждой стороны
  • сортировка вариантов по степени переполнения
  • выбор оптимального placement

Это делает поведение адаптивным и независимым от конкретной верстки.

Поведение при недостатке места со всех сторон

Если ни один вариант полностью не помещается:

  • выбирается положение с минимальным переполнением
  • далее preventOverflow корректирует позицию внутри допустимой области

Таким образом достигается максимально возможная видимость popper-элемента даже в ограниченных условиях.