Html – iframe prevents iScroll scrolling on mobile Safari

htmliframeiosiscrollscroll

I am using iScroll on my mobile enable website (using iPhone here) to scroll inside a div.

In this this div, I have an iframe with a fixed height like this:

<body>
  <div id="iscroller">
    <iframe id="theIframe"></iframe>
    Other stuff
  </div>
</body>

Now, while scrolling within the div, everything works as expected but I cannot scroll when the scrolling gesture begins on the iframe.

The problem is described here pretty well: https://github.com/cubiq/iscroll/issues/41

So, I used the css workaround from that post by applying pointer-events:none to the iframe.

Now scrolling works perfectly but I cannot click any links which are defined within the iframe because all click/touch events on the iframe seems to be blocked due to pointer-events: none.

So, I thought:

"Ok, while the user scrolls, I need pointer-events:none. If he is
not scrolling (and instead clicking), I must set pointer-events:auto
in order to let the click/touch events pass."

So I did this:

CSS

#theIframe{pointer-events:none}

JavaScript

$("#theIframe").bind("touchstart", function(){
  // Enable click before click is triggered
  $(this).css("pointer-events", "auto");
});

$("#theIframe").bind("touchmove", function(){
  // Disable click/touch events while scrolling
  $(this).css("pointer-events", "none");
});

Even adding this doesn't work:

$("#theIframe").bind("touchend", function(){
  // Re-enable click/touch events after releasing
  $(this).css("pointer-events", "auto");
});

No matter what I do: Either scrolling doesn't work or clicking the link inside the iframe doesn't work.

Doesn't work. Any ideas?

Best Answer

I found the perfect solution. Works great on iOS and Android.

The basic idea is to put a div layer on top of that iframe. This way scrolling works smoothly.

If the user wants to tap/click on an element on that iframe I simply catch that click on the layer, save the x and y coordinates and trigger a click event on the iframe's content at these coordinates:

HTML:

<div id="wrapper">
    <div id="layer"></div>
    <iframe id="theIframe"></iframe>
</div>
Other stuff

CSS:

#layer{
    position:absolute;
    opacity:0;
    width:100%;
    height:100%;
    top:0;
    left:0;
    right:0;
    bottom:0;
    z-index:2
}

JavaScript:

$('#layer').click(function(event){
    var iframe = $('#theIframe').get(0);
    var iframeDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;

    // Find click position (coordinates)
    var x = event.offsetX;
    var y = event.offsetY;

    // Trigger click inside iframe
    var link = iframeDoc.elementFromPoint(x, y);
    var newEvent = iframeDoc.createEvent('HTMLEvents');
    newEvent.initEvent('click', true, true);
    link.dispatchEvent(newEvent);
});