Как сделать так, чтобы у 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" кнопка позволяет мне нажать на нее.

Z-Index

РЕДАКТИРОВАТЬ: Если вы хотите сделать 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 не активируются.

Другие вопросы по тегам