Функциональный offset

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

Функциональная форма offset предоставляет максимальную гибкость, позволяя вычислять смещение динамически на основе текущего состояния — размеров элементов, выбранного размещения (placement) и других параметров.


Базовая концепция смещения

Смещение задаётся в виде двух значений:

  • skidding — сдвиг вдоль основной оси reference-элемента
  • distance — сдвиг вдоль оси, перпендикулярной reference

Пример статического offset:

{
  name: 'offset',
  options: {
    offset: [0, 10]
  }
}

В этом случае popper будет отодвинут на 10 пикселей от reference.


Функциональный offset: динамическое вычисление

Функциональный вариант позволяет передать не массив, а функцию:

{
  name: 'offset',
  options: {
    offset: ({ placement, reference, popper }) => {
      return [skidding, distance];
    }
  }
}

Функция получает объект с параметрами:

  • placement — текущее положение (top, bottom-start и т.д.)
  • reference — размеры и координаты reference-элемента
  • popper — размеры popper-элемента

Структура аргументов функции

offset: ({ placement, reference, popper }) => {
  console.log(placement);
  console.log(reference.width, reference.height);
  console.log(popper.width, popper.height);

  return [0, 8];
}

Объекты reference и popper содержат:

  • width / height
  • x / y координаты
  • top / left / right / bottom

Это позволяет учитывать реальные размеры элементов при вычислении смещения.


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

1. Разное смещение для разных положений

offset: ({ placement }) => {
  if (placement.startsWith('top')) {
    return [0, 12];
  }
  if (placement.startsWith('bottom')) {
    return [0, 6];
  }
  return [0, 8];
}

Такой подход полезен, когда визуальное расстояние должно отличаться в зависимости от направления.


2. Учет размеров popper

offset: ({ popper }) => {
  return [0, popper.height / 2];
}

Используется для центрирования или создания адаптивного отступа.


3. Учет размеров reference

offset: ({ reference }) => {
  return [reference.width / 4, 10];
}

Позволяет смещать popper относительно ширины якорного элемента.


4. Смещение с учётом пользовательских условий

offset: ({ placement, reference }) => {
  const isWide = reference.width > 200;

  if (isWide) {
    return [10, 20];
  }

  return [0, 8];
}

Применяется при адаптивных интерфейсах.


Работа с осями

Направление смещения зависит от placement:

Placement Основная ось Перпендикулярная ось
top / bottom X Y
left / right Y X

Пример:

offset: ({ placement }) => {
  if (placement === 'left') {
    return [10, 0]; // сдвиг по вертикали
  }
  return [0, 10]; // сдвиг по вертикали вниз
}

Комбинирование с другими модификаторами

offset часто используется вместе с:

  • flip — для изменения стороны при нехватке места
  • preventOverflow — чтобы popper не выходил за границы
  • arrow — для позиционирования стрелки

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


Распространённые ошибки

1. Игнорирование placement

offset: () => [0, 10]

Фиксированное значение может выглядеть некорректно при смене позиции.


2. Неправильное понимание осей

Попытка смещать по X при вертикальном placement может привести к неожиданным результатам.


3. Использование тяжёлых вычислений

Функция вызывается часто, поэтому сложные операции могут повлиять на производительность.


Оптимизация и рекомендации

  • Использование простых условий вместо сложных вычислений
  • Кэширование значений при необходимости
  • Минимизация работы внутри функции
  • Проверка поведения при всех placement

Расширенные сценарии

Адаптивные интерфейсы

offset: ({ reference }) => {
  const isMobile = window.innerWidth < 768;

  return isMobile ? [0, 4] : [0, 12];
}

Интеграция с UI-фреймворками

В сочетании с библиотеками интерфейсов (например, Bootstrap, Material UI) функциональный offset позволяет:

  • подгонять всплывающие элементы под дизайн-систему
  • учитывать кастомные отступы
  • синхронизировать поведение компонентов

Смещение для стрелки (arrow alignment)

offset: ({ popper }) => {
  return [0, popper.height / 2 - 5];
}

Используется для точного выравнивания стрелки относительно центра.


Взаимодействие с системой координат Popper

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

  • bounding client rect
  • viewport
  • scroll offsets

Функциональный offset применяется после вычисления базовой позиции, что делает его финальным этапом корректировки.


Итоговая модель работы

  1. Определяется базовое положение (placement)
  2. Применяются модификаторы (flip, preventOverflow)
  3. Вызывается функция offset
  4. Итоговая позиция корректируется

Функциональный offset становится ключевым инструментом для точной настройки поведения popper-элементов, особенно в сложных и динамических интерфейсах.