Как сделать так, чтобы у iframe были события указателя: нет; но не на div внутри этого?
У меня есть iframe с наследственным pointer-events: none;
но когда я вставил <div>
внутри фрейма с pointer-events: auto;
div не будет реагировать на нажатия или любые события наведения мыши.
Причина этого заключается в том, что iframe
находится внутри <div style="position:fixed;">
так что вроде как маленькое меню. но я бы хотел, чтобы пользователь нажимал на iframe
, но не через ссылки и divs в iframe.
И да, для этого абсолютно необходимо оставаться в фрейме.
Как я мог обойти это? Могу ли я вообще обойти это?
Вот простой пример: http://jsfiddle.net/MarcGuiselin/yLo119sw/2
7 ответов
Я много искал и сам нашел обходное решение.
// the iframe element
const frame = document.getElementsByTagName("iframe")[0];
frame.onload = function () {
const frameDocument = frame.contentDocument;
document.addEventListener("mousemove", onMouseMove, true);
frameDocument.addEventListener("mousemove", onMouseMove, true);
function onMouseMove(e) {
let coord;
if (e.currentTarget === document) {
coord = {
x: e.pageX - frame.offsetLeft,
y: e.pageY - frame.offsetTop,
};
} else {
coord = { x: e.clientX, y: e.clientY };
}
const el = frameDocument.elementFromPoint(coord.x, coord.y);
// you can compare to your own element if needed
frame.style.pointerEvents = !el || el === frameDocument.body ? "none" : "auto";
}
};
Iframe будет автоматически переключать pointer-events
и все события работают без сбоев.
То, что мы хотим, не разрешено спецификацией, по крайней мере, не с абсолютно позиционированным iframe.
Мы все хотим сделать одно и то же:
- Визуализация контейнера (обычно для расширения Chrome), расположенного над страницей и заполняющего область просмотра.
- Запретить не позволять самому контейнеру захватывать события указателя
- Разрешить дочерним элементам контейнера захватывать события указателя
Это позволяет нам «кликать» по абсолютно позиционированному блоку, но при этом взаимодействовать с его дочерними элементами, которые могут быть кнопками или просто блоками с событиями наведения или чем-то еще.
Мы можем добиться такого поведения тогда и только тогда, когда ящики используют один и тот же документ. Отключение событий указателя для абсолютно позиционированногоотключает их для всех своих дочерних элементов.
Альтернативным подходом является рендеринг содержимого непосредственно в документ , т. е. в Shadow DOM для песочницы стилей. Это единственный способ добиться такого поведения, поскольку мы его ищем, и именно так я ранее подошел к проблеме, прежде чем пытаться выполнить рефакторинг в iframe и обнаружил, что его нельзя воспроизвести таким образом.
См. https://iframe-pointer-events.vercel.app для демонстрации.
Вы работаете с position:absolute
в соответствии с примером, который вы загрузили на jsfiddle... Добавление z-index
на кнопку "Вы не можете щелкнуть меня, потому что я за iframe" кнопка позволяет мне нажать на нее.
РЕДАКТИРОВАТЬ: Если вы хотите сделать pointer-events: none;
везде, кроме одного div
Вы можете добавить pointer-events
в каждом element
вместо iframe
, Согласно вашему примеру на скрипке, если вы хотите сохранить Николас Кейдж, но заблокировать другие события, вы можете сделать что-то вроде этого:
switchbutton.onclick=function(){
this.innerHTML="reload to reset";
//iframe.style.pointerEvents="none";
cantclick.innerHTML="You can click me now! :)";
iframe.contentDocument.body.innerHTML="<button>You can't click me now because my parent iframe is click-through! :(</button><br>or save this gorgeous image of your favorite actor which may or may not be relavant to the problem.<br><img id='nicholasCage' src='http://media2.popsugar-assets.com/files/2014/01/06/008/n/1922283/131b4126c7b8738f_thumb_temp_image333458751389045360.jpg.xxxlarge/i/Best-Nicolas-Cage-Memes.jpg'/>";
var iframeBody = iframe.contentDocument,
elements = iframeBody.querySelectorAll("*"),
i,
len = elements.length;
for(i=0;i<len;i++){
elements[i].style.pointerEvents="none";
}
iframeBody.getElementById("nicholasCage").style.pointerEvents="all";
}
Если вы можете использовать JQuery, вы можете сделать это быстрее, просто используя $("iframe *").css("pointer-events","none");
Вы никак не можете это сделать, так как это будет еще одна проблема безопасности наряду с перехватом кликов.
Стили внутри iframe никак не взаимодействуют со стилями внутри хост-сайта. Так что если вы даже установите z-index/pointer-events или что-то еще в iframe и попытаетесь переопределить правило внутри него, это никак не будет применяться к правилам хост-сайта.
Так в чем же решение? Вы должны разделить свой iframe на несколько и возиться с их позицией.
если вы можете вернуть это, поместите элемент click в качестве оболочки iframe:
<button><iframe></iframe></button>
button {
display : block; /* or inline-block */
}
button iframe {
pointer-events : none;
position: relative;
z-index : 0;
}
Вы пробовали это?
pointer-events: inherit;
Я знаю, что вы уже получили свой ответ, но я подумал, что это тоже может сработать.
Не давайте весь iframe pointer-events: none
, Просто внутри iframe
поставить правило CSS body * { pointer-events: none;}
Таким образом, iframe не блокирует события, однако элементы внутри iframe не активируются.