Popper.js — это мощная библиотека для управления позиционированием всплывающих элементов относительно других элементов на странице. Основная задача библиотеки — корректно вычислять положение поппера (tooltip, dropdown, modal и т. д.) с учётом границ окна, смещения и взаимодействия с другими элементами DOM. В современных приложениях Popper.js используется совместно с фреймворками вроде React, Vue или Angular, но в чистом JavaScript она также функционирует эффективно.
Библиотека строится вокруг Popper Instance —
объекта, который управляет позиционированием. Создаётся он через функцию
createPopper(reference, popper, options):
import { createPopper } from '@popperjs/core';
const reference = document.querySelector('#button');
const popper = document.querySelector('#tooltip');
const popperInstance = createPopper(reference, popper, {
placement: 'top',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
{
name: 'preventOverflow',
options: {
boundary: 'viewport',
},
},
],
});
top, bottom, left,
right, с вариациями -start и
-end).Модификаторы — это ядро гибкости Popper.js. Они позволяют настраивать
смещение, предотвращать выход поппера за границы экрана, управлять
стратегией позиционирования (absolute или
fixed) и многое другое.
Основные модификаторы:
offset — задаёт смещение относительно reference.
{
name: 'offset',
options: { offset: [10, 20] },
}
Первый параметр массива отвечает за смещение по основной оси, второй — по перекрестной.
preventOverflow — предотвращает выход поппера за границы заданного контейнера.
{
name: 'preventOverflow',
options: { boundary: document.body },
}flip — позволяет автоматически менять расположение поппера, если выбранное placement не помещается на экране.
{
name: 'flip',
options: { fallbackPlacements: ['top', 'right', 'bottom'] },
}arrow — используется для стрелок поппера.
{
name: 'arrow',
options: { element: '.tooltip-arrow' },
}Popper.js хранит внутреннее состояние в объекте
state, который содержит данные о позиционировании,
размерах элементов и вычисленных стилях. Объект state
состоит из следующих ключевых полей:
{ reference, popper, arrow }const state = popperInstance.state;
console.log(state.placement); // 'top'
console.log(state.rects.reference.width); // ширина элемента reference
В Popper.js state не рекомендуется изменять напрямую,
однако можно использовать модификаторы для
динамического обновления данных. Каждый модификатор получает доступ к
state и может изменять его свойства.
const customModifier = {
name: 'logPlacement',
enabled: true,
phase: 'write',
fn({ state }) {
console.log('Текущее положение:', state.placement);
state.styles.popper.transform += ' rotate(5deg)';
},
};
read,
main, write, afterWrite)setOptionsЕсли необходимо обновить смещения, placement или модификаторы после
создания popper, используется метод setOptions:
popperInstance.setOptions({
placement: 'bottom-start',
modifiers: [
{
name: 'offset',
options: { offset: [0, 16] },
},
],
});
После этого автоматически пересчитывается state, и
поппер обновляется.
Popper.js обеспечивает автоматическое обновление при
изменении размеров reference. Для этого используется метод
update:
popperInstance.update();
Если reference или popper динамически изменяют размер, вызов
update пересчитывает положение и стили. В современных
приложениях удобно сочетать это с ResizeObserver:
const observer = new ResizeObserver(() => {
popperInstance.update();
});
observer.observe(reference);
observer.observe(popper);
В React часто используют useEffect для создания
popper:
import { createPopper } from '@popperjs/core';
import { useRef, useEffect } from 'react';
function Tooltip({ children, target }) {
const popperRef = useRef(null);
const instanceRef = useRef(null);
useEffect(() => {
instanceRef.current = createPopper(target.current, popperRef.current, {
placement: 'right',
});
return () => instanceRef.current.destroy();
}, [target]);
return <div ref={popperRef}>{children}</div>;
}
Vue предоставляет аналогичный подход через директивы или Composition API.
Popper.js поддерживает две стратегии:
position: relative/absolute контейнера.createPopper(reference, popper, {
strategy: 'fixed',
});
Стратегия влияет на расчёт state.rects и поведение при
скролле.
Модификатор preventOverflow позволяет задать разные типы
границ:
{
name: 'preventOverflow',
options: {
altAxis: true, // учитывать вторичную ось
tether: false, // отключает «привязку» к reference
padding: 8, // отступ от границ
},
}
Это особенно важно для адаптивных интерфейсов, где popper должен оставаться видимым даже при малых разрешениях.
Popper.js создаёт мощный, но управляемый механизм работы с
динамическими элементами. Объект state содержит всю
необходимую информацию о позиционировании, модификаторах и стилях.
Основные способы работы с ним:
setOptions и update для пересчёта
при изменении параметровЭти инструменты позволяют строить сложные интерфейсы с всплывающими элементами, которые корректно реагируют на изменение размеров, скроллинг и адаптивность.