Popper.js предоставляет гибкие механизмы позиционирования элементов
относительно других элементов в DOM. Когда целевым элементом является
iFrame, возникают специфические нюансы, связанные с изолированным
контекстом окна (window) и документом
(document). Эти нюансы необходимо учитывать при создании
всплывающих подсказок, тултипов или других плавающих элементов поверх
iFrame.
Изолированный контекст Каждый iFrame содержит
собственный document и window. Попытка
напрямую позиционировать элемент из родительского документа относительно
элемента внутри iFrame или наоборот приведет к ошибкам, если не
учитывать этот изолированный контекст.
Смещение относительно документа Координаты элементов внутри iFrame вычисляются относительно самого iFrame, а не всей страницы. При расчете позиции для Popper.js нужно учитывать смещение iFrame относительно окна браузера и прокрутку страницы.
Для корректного позиционирования необходимо учитывать родительский контейнер iFrame:
import { createPopper } from '@popperjs/core';
// Элемент внутри iFrame
const iframe = document.querySelector('#my-iframe');
const iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
const reference = iframeDocument.querySelector('#reference');
const tooltip = iframeDocument.createElement('div');
iframeDocument.body.appendChild(tooltip);
createPopper(reference, tooltip, {
placement: 'top',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
],
});
Ключевые моменты:
iframe.contentDocument или
iframe.contentWindow.document для доступа к DOM внутри
iFrame.offset,
flip, preventOverflow) работает без изменений,
если Popper создается внутри iFrame.Если требуется позиционировать элемент в родительском документе относительно элемента внутри iFrame, необходимо учитывать смещение iFrame и прокрутку страницы:
const iframe = document.querySelector('#my-iframe');
const iframeRect = iframe.getBoundingClientRect();
const reference = iframe.contentDocument.querySelector('#reference');
const referenceRect = reference.getBoundingClientRect();
const tooltip = document.createElement('div');
document.body.appendChild(tooltip);
createPopper(
{
getBoundingClientRect: () => ({
width: referenceRect.width,
height: referenceRect.height,
top: iframeRect.top + referenceRect.top,
bottom: iframeRect.top + referenceRect.bottom,
left: iframeRect.left + referenceRect.left,
right: iframeRect.left + referenceRect.right,
}),
clientWidth: referenceRect.width,
clientHeight: referenceRect.height,
},
tooltip,
{
placement: 'right',
}
);
Важные моменты:
reference с методом
getBoundingClientRect для Popper.js позволяет корректно
вычислять позицию относительно родительского документа.Кросс-доменные iFrame Если iFrame загружает
контент с другого домена, доступ к его contentDocument или
contentWindow запрещен политикой CORS. В этом случае прямое
позиционирование через Popper невозможно. Решением может быть обмен
координатами через postMessage.
Прокрутка iFrame Внутри iFrame может быть
собственная прокрутка. Для корректного позиционирования нужно учитывать
scrollTop и scrollLeft iFrame при вычислении
координат.
Перерисовка при изменении размеров Popper.js
автоматически обновляет позицию элементов при изменении размеров окна
браузера, но при работе с iFrame может потребоваться дополнительный
вызов update() при изменении размеров iFrame или его
содержимого.
position: absolute внутри iFrame для
Popper-элементов, чтобы избежать конфликтов с CSS родительского
документа.update() при
динамическом изменении размеров iFrame, используя
requestAnimationFrame для оптимизации.popperInstance.forceUpdate() вместо стандартного
update(), если требуется мгновенная корректировка
позиции.Popper.js предоставляет гибкий инструмент для работы с iFrame, но
требует точного контроля контекста документа и учета смещений.
Использование кастомных методов getBoundingClientRect и
правильное управление DOM внутри iFrame позволяет создавать стабильные,
точные и отзывчивые всплывающие элементы, независимо от структуры
страницы и вложенности iFrame.