Новые возможности v2

Вторая версия Popper.js представляет собой серьёзную переработку внутренней архитектуры. Основной акцент сделан на модульности, производительности и гибкости настройки. В отличие от первой версии, где логика позиционирования была более монолитной, v2 строится вокруг системы модификаторов (modifiers), которые работают как конвейер обработки данных.

Ключевые изменения:

  • переход к функциональной архитектуре
  • строгая изоляция логики в модификаторах
  • улучшенная система вычисления координат
  • уменьшенный размер бандла за счёт tree-shaking
  • отказ от устаревших API

Система модификаторов (Modifiers)

Общая концепция

Модификаторы — это независимые функции, которые последовательно изменяют состояние поппера. Каждый модификатор выполняет строго определённую задачу:

  • вычисление позиции
  • предотвращение выхода за границы
  • добавление отступов
  • применение стилей

Каждый модификатор описывается объектом:

const modifier = {
  name: 'example',
  enabled: true,
  phase: 'main',
  fn({ state, options }) {
    // логика
  }
};

Фазы выполнения

В v2 введено понятие фаз, что делает порядок выполнения предсказуемым:

  • beforeRead
  • read
  • afterRead
  • beforeMain
  • main
  • afterMain
  • beforeWrite
  • write
  • afterWrite

Это позволяет:

  • избегать лишних reflow/repaint
  • оптимизировать доступ к DOM
  • точно контролировать последовательность операций

Новая модель позиционирования

Абсолютное и фиксированное позиционирование

В v2 улучшена поддержка двух режимов:

  • position: absolute
  • position: fixed

Теперь выбор режима напрямую влияет на расчёты:

createPopper(reference, popper, {
  strategy: 'fixed'
});

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

  • fixed игнорирует прокрутку контейнеров
  • absolute учитывает ближайший позиционированный родитель

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

Отвечает за преобразование вычисленных координат в CSS-стили.

{
  name: 'computeStyles',
  options: {
    gpuAcceleration: true,
    adaptive: true
  }
}

Новые возможности:

  • GPU-ускорение через transform: translate3d
  • адаптивные стили для разных размеров экрана
  • контроль над субпиксельной точностью

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

Отделён от вычислений, отвечает только за применение стилей:

{
  name: 'applyStyles'
}

Это разделение даёт:

  • возможность отключить автоматическое применение
  • интеграцию с фреймворками (React, Vue)
  • ручной контроль DOM-обновлений

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

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

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

Поддержка функций:

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

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

Автоматически меняет положение поппера, если он не помещается:

{
  name: 'flip',
  options: {
    fallbackPlacements: ['top', 'right']
  }
}

Улучшения v2:

  • гибкая настройка fallback-цепочек
  • учёт границ viewport и контейнеров
  • более точные расчёты переполнения

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

Предотвращает выход поппера за пределы заданной области:

{
  name: 'preventOverflow',
  options: {
    boundary: 'viewport',
    padding: 8
  }
}

Новые параметры:

  • altBoundary
  • tether — “привязка” к reference
  • точная настройка поведения по осям

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

Обеспечивает корректное позиционирование стрелки:

{
  name: 'arrow',
  options: {
    element: arrowElement
  }
}

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

  • автоматический расчёт положения
  • учёт размеров стрелки
  • интеграция с overflow-логикой

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

Определяет, виден ли popper:

{
  name: 'hide'
}

Добавляет в state:

  • data-popper-reference-hidden
  • data-popper-escaped

Позволяет:

  • скрывать tooltip, если reference вне экрана
  • управлять видимостью через CSS

Виртуальные элементы (Virtual Elements)

Одно из ключевых нововведений — возможность использовать виртуальные reference-элементы.

const virtualElement = {
  getBoundingClientRect: () => ({
    width: 0,
    height: 0,
    top: 100,
    left: 200,
    right: 200,
    bottom: 100
  })
};

Применение:

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

Полный контроль над жизненным циклом

Создание popper-инстанса:

const instance = createPopper(reference, popper, options);

Методы управления:

instance.update();
instance.forceUpdate();
instance.destroy();

Отличия:

  • update() — асинхронное обновление
  • forceUpdate() — синхронное
  • улучшенная производительность при частых изменениях

Поддержка tree-shaking

Popper v2 полностью модульный. Использование только необходимых частей:

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

Преимущества:

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

Улучшенная работа с границами (Boundaries)

Границы теперь гибко настраиваются:

{
  name: 'preventOverflow',
  options: {
    boundary: document.body,
    rootBoundary: 'viewport'
  }
}

Различие:

  • boundary — локальные ограничения
  • rootBoundary — глобальные (viewport или document)

Расширяемость и кастомные модификаторы

Создание собственного модификатора:

const customModifier = {
  name: 'custom',
  enabled: true,
  phase: 'main',
  fn({ state }) {
    state.styles.popper.background = 'red';
  }
};

Подключение:

createPopper(reference, popper, {
  modifiers: [customModifier]
});

Возможности:

  • вмешательство в любой этап вычислений
  • изменение state
  • добавление новых данных

Улучшения производительности

Основные факторы:

  • минимизация DOM-доступа
  • batching операций
  • разделение read/write фаз
  • использование GPU

Результаты:

  • меньше layout thrashing
  • стабильная работа при анимациях
  • высокая точность позиционирования

Работа с адаптивностью

Popper v2 учитывает:

  • изменение размеров окна
  • скролл контейнеров
  • изменение размеров reference

Автоматическое обновление происходит через:

  • ResizeObserver
  • MutationObserver (в некоторых случаях)

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

Благодаря разделению логики и применения стилей:

  • легко интегрируется с React (через хуки)
  • используется в Vue и Angular
  • совместим с headless UI-подходом

Изменения API по сравнению с v1

Удалено:

  • устаревшие опции
  • автоматическая магия позиционирования

Добавлено:

  • строгая типизация (в TypeScript)
  • декларативные модификаторы
  • предсказуемый lifecycle

Работа с placement

Поддерживаемые позиции:

  • top, bottom, left, right
  • вариации: -start, -end
placement: 'top-start'

Улучшения:

  • точное выравнивание
  • корректная работа в RTL
  • учёт размеров элементов

Дебаг и инспекция состояния

В объекте state содержится вся информация:

fn({ state }) {
  console.log(state);
}

Включает:

  • координаты
  • placement
  • размеры элементов
  • данные модификаторов

Это делает отладку прозрачной и удобной.


Переход на v2: ключевые моменты

  • требуется переписать конфигурацию модификаторов
  • убрать устаревшие опции
  • адаптировать кастомную логику под новую архитектуру

Основная сложность перехода связана с изменением мышления: от конфигурационного подхода к композиции модификаторов.


Итоговые особенности версии 2

  • модульная архитектура
  • высокая производительность
  • расширяемость
  • поддержка виртуальных элементов
  • точный контроль позиционирования
  • современный API

Popper.js v2 представляет собой полноценный инструмент для сложных сценариев позиционирования, пригодный как для простых tooltip, так и для комплексных UI-компонентов.