Fallback стратегии

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

Popper.js использует концепцию modifiers для управления поведением поппера, и fallback-стратегии реализуются через модификатор flip, который автоматически изменяет позицию элемента, если изначально заданная позиция не помещается.


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

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

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

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

createPopper(reference, popper, {
  placement: 'top',
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['right', 'bottom', 'left'],
        padding: 8
      }
    }
  ]
});

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

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

Алгоритм работы fallback-стратегии

  1. Поппер пытается разместиться в основной позиции (placement).
  2. Если элемент выходит за границы видимой области или перекрывается с контейнером, Popper.js проверяет fallback-позиции.
  3. Первая подходящая fallback-позиция используется для рендеринга.
  4. Если ни одна из fallback-позиций не подходит, применяется auto-определение позиции, когда Popper.js выбирает наиболее свободное место.

Popper.js учитывает не только размеры поппера, но и размеры его reference-элемента и ограничения boundary (контейнера, viewport, или кастомного элемента).


Настройка fallback-стратегий через flip и preventOverflow

Модификаторы flip и preventOverflow тесно связаны. preventOverflow ограничивает поппер внутри определенной области, а flip использует эти ограничения для выбора fallback-позиции.

createPopper(reference, popper, {
  placement: 'bottom',
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['top', 'right', 'left']
      }
    },
    {
      name: 'preventOverflow',
      options: {
        boundary: 'viewport',
        padding: 10
      }
    }
  ]
});

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

  • boundary задает ограничивающий контейнер: 'viewport', 'clippingParents' или конкретный элемент.
  • padding указывает минимальный отступ от границ.
  • Поппер сначала проверяет возможность размещения, учитывая preventOverflow, а затем применяет flip при необходимости.

Динамическая fallback-логика

В некоторых случаях набор fallback-позиций может зависеть от состояния интерфейса. Popper.js поддерживает функции в options, что позволяет динамически вычислять позиции:

createPopper(reference, popper, {
  placement: 'top',
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ({ placement, reference, popper }) => {
          if (window.innerWidth < 500) {
            return ['bottom', 'right'];
          }
          return ['right', 'left', 'bottom'];
        }
      }
    }
  ]
});
  • Функция получает текущую placement, reference и popper.
  • Возвращаемый массив используется как список fallback-позиций.
  • Позволяет учитывать размеры окна, состояние интерфейса или кастомные ограничения.

Advanced: множественные fallback-стратегии

Для сложных интерфейсов можно комбинировать несколько стратегий:

  1. Основная позиция.
  2. fallbackPlacements через flip.
  3. Автоматическое определение через auto placement.
  4. Ограничение через preventOverflow с кастомным boundary.
createPopper(reference, popper, {
  placement: 'auto',
  modifiers: [
    {
      name: 'flip',
      options: {
        fallbackPlacements: ['top-start', 'bottom-end', 'right-start']
      }
    },
    {
      name: 'preventOverflow',
      options: {
        boundary: document.querySelector('#container'),
        tether: true,
        padding: 5
      }
    }
  ]
});
  • Использование tether гарантирует, что поппер будет привязан к reference, даже если все fallback-позиции ограничены.
  • auto позволяет Popper.js самому выбирать оптимальную позицию, комбинируя с fallback.

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

  • Всегда указывать fallback-позиции для интерфейсов с ограниченным пространством.
  • Использовать preventOverflow для управления выходом за границы.
  • Комбинировать fallback-списки с динамическими функциями для адаптивных интерфейсов.
  • Следить за порядком элементов в fallbackPlacements, так как Popper.js проверяет их строго по очереди.
  • Для сложных компонентов использовать auto placement как завершающий уровень fallback.

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