Вторая версия Popper.js представляет собой серьёзную переработку внутренней архитектуры. Основной акцент сделан на модульности, производительности и гибкости настройки. В отличие от первой версии, где логика позиционирования была более монолитной, v2 строится вокруг системы модификаторов (modifiers), которые работают как конвейер обработки данных.
Ключевые изменения:
Модификаторы — это независимые функции, которые последовательно изменяют состояние поппера. Каждый модификатор выполняет строго определённую задачу:
Каждый модификатор описывается объектом:
const modifier = {
name: 'example',
enabled: true,
phase: 'main',
fn({ state, options }) {
// логика
}
};
В v2 введено понятие фаз, что делает порядок выполнения предсказуемым:
beforeReadreadafterReadbeforeMainmainafterMainbeforeWritewriteafterWriteЭто позволяет:
В v2 улучшена поддержка двух режимов:
position: absoluteposition: fixedТеперь выбор режима напрямую влияет на расчёты:
createPopper(reference, popper, {
strategy: 'fixed'
});
Особенности:
fixed игнорирует прокрутку контейнеровabsolute учитывает ближайший позиционированный
родительcomputeStylesОтвечает за преобразование вычисленных координат в CSS-стили.
{
name: 'computeStyles',
options: {
gpuAcceleration: true,
adaptive: true
}
}
transform: translate3dapplyStylesОтделён от вычислений, отвечает только за применение стилей:
{
name: 'applyStyles'
}
Это разделение даёт:
offsetПозволяет задавать смещение поппера относительно опорного элемента:
{
name: 'offset',
options: {
offset: [0, 10]
}
}
offset: ({ placement, reference, popper }) => {
return [0, reference.height / 2];
}
flipАвтоматически меняет положение поппера, если он не помещается:
{
name: 'flip',
options: {
fallbackPlacements: ['top', 'right']
}
}
preventOverflowПредотвращает выход поппера за пределы заданной области:
{
name: 'preventOverflow',
options: {
boundary: 'viewport',
padding: 8
}
}
altBoundarytether — “привязка” к referencearrowОбеспечивает корректное позиционирование стрелки:
{
name: 'arrow',
options: {
element: arrowElement
}
}
hideОпределяет, виден ли popper:
{
name: 'hide'
}
Добавляет в state:
data-popper-reference-hiddendata-popper-escapedПозволяет:
Одно из ключевых нововведений — возможность использовать виртуальные 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() — синхронноеPopper v2 полностью модульный. Использование только необходимых частей:
import { createPopper } from '@popperjs/core';
Границы теперь гибко настраиваются:
{
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]
});
Popper v2 учитывает:
Автоматическое обновление происходит через:
Благодаря разделению логики и применения стилей:
Поддерживаемые позиции:
top, bottom, left,
right-start, -endplacement: 'top-start'
В объекте state содержится вся информация:
fn({ state }) {
console.log(state);
}
Это делает отладку прозрачной и удобной.
Основная сложность перехода связана с изменением мышления: от конфигурационного подхода к композиции модификаторов.
Popper.js v2 представляет собой полноценный инструмент для сложных сценариев позиционирования, пригодный как для простых tooltip, так и для комплексных UI-компонентов.