13

...without limiting the scroll inside the iframe or the need to specifically name/tag all scrollable elements.

Imagine google maps widget embedded in parent page. When you zoom in the widget you don't want the parent page to scroll, obviously.

I thought an answer to my previous question solved the problem:

While scrolling inside an iframe, the body doesn't know anything about what happens there. But when iframe scroller reach the bottom or the top, it pass scrolling to body.

Cancel the event that propagates from the iframe.

But the solution does not work in Firefox because Firefox will not - by design - propagate events captured by iframe to the parent page, yet strangely it will scroll the parent page. See jsfiddle here.

$('body').bind('mousewheel DOMMouseScroll', onWheel);

function onWheel (e){
    if (e.target === iframe)
        e.preventDefault();
    console.log(e);
}

So, how do I prevent page from scrolling when user zooms content in embedded iframe, in Firefox?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
daniel.sedlacek
  • 8,129
  • 9
  • 46
  • 77
  • Because Firefox uses the DOMMouseScroll event, I would try changing $('body') to $(document), maybe it could work but Im not definetely sure. Worth a try – GOSCHEN Aug 24 '15 at 09:14
  • @GOSCHEN that is not the problem, "Firefox will not - by design - propagate events captured by iframe to the parent page" – daniel.sedlacek Aug 24 '15 at 09:21
  • 1
    If you can still capture the scroll event (on the parent page), maybe you can check the mouse position against the iframe position: if the mouse is inside, cancel the scrolling – oliverpool Aug 25 '15 at 12:45

3 Answers3

18

Since it is a bug in Firefox, the workaround is to work directly with the scroll event, instead of the mousewheel / DOMMouseScroll ones.

The way I did: When user enters the mouse over the iframe, I set a flag to true, and when he leaves the mouse out there, I set it back to false.

Then, when user tries to scroll, but the mouse arrow is inside the iframe, I prevent the parent window scrolling. But, unfortunately, you can't prevent the window scrolling with the usual e.preventDefault() method, so we still need another workaround here, forcing the window to scroll exactly to the X and Y positions it was already before.

The full code:

(function(w) {
    var s = { insideIframe: false } 

    $(iframe).mouseenter(function() {
        s.insideIframe = true;
        s.scrollX = w.scrollX;
        s.scrollY = w.scrollY;
    }).mouseleave(function() {
        s.insideIframe = false;
    });

    $(document).scroll(function() {
        if (s.insideIframe)
            w.scrollTo(s.scrollX, s.scrollY);
    });
})(window);

I've created an immediately executed function to prevent defining the s variable in the global scope.

Fiddle working: http://jsfiddle.net/qznujqjs/16/


Edit

Since your question was not tagged with jQuery (although inside it, you've showed a code using the library), the solution with vanilla JS is as simple as the above one:

(function(w) {
    var s = { insideIframe: false } 

    iframe.addEventListener('mouseenter', function() {
        s.insideIframe = true;
        s.scrollX = w.scrollX;
        s.scrollY = w.scrollY;
    });
    
    iframe.addEventListener('mouseleave', function() {
        s.insideIframe = false;
    });

    document.addEventListener('scroll', function() {
        if (s.insideIframe)
            w.scrollTo(s.scrollX, s.scrollY);
    });
})(window);
Community
  • 1
  • 1
Buzinas
  • 11,597
  • 2
  • 36
  • 58
  • That's very elegant hack! – daniel.sedlacek Aug 31 '15 at 09:24
  • @Buzinas I want parent page to scroll even my mouse is on iframe but not happening in firefox, see this fiddle http://jsfiddle.net/shmdhussain/jop93dhr/2/ – Mohamed Hussain Sep 14 '15 at 07:20
  • Thank's , this work very good ! =D and I has refactored a bit your first code but, i only changed how to do the events. I made them like this : `` $('my_container').on('mouseenter', 'iframe' ,function() {})´´ – borjis May 30 '17 at 12:18
2

Given all the prerequisites, I think the following is the sanest way to make this work in Firefox.

Wrap your iframe with a div which is a little bit shorter to enable vertical scrolling in it:

<div id="wrapper" style="height:190px; width:200px; overflow-y: auto; overflow-x: hidden;">
  <iframe id="iframeid" height="200px" width="200px" src="about:blank">
  </iframe>
</div>

Now you can center the iframe vertically and re-position it every time the wrapper receives a scroll event (it will occur when a user tries to scroll away at frame edges):

var topOffset = 3;

wrapper.scrollTop(topOffset);

wrapper.on("scroll", function(e) {
    wrapper.scrollTop(topOffset);
});

Combine this with your previous fix for Chrome, and it should cover all major browsers. Here is a working example - http://jsfiddle.net/o2tk05ab/5/

The only outstanding issue will be the visible vertical scrollbar on a wrapper div. There are several ways to go about it, for instance - Hide scroll bar, but still being able to scroll

Community
  • 1
  • 1
Roman Pletnev
  • 5,958
  • 2
  • 21
  • 28
0

I think that will solve your problem it solved mine

    var myElem=function(event){
  return $(event.toElement).closest('.slimScrollDiv')
}

$(document).mouseover(function(e){
     window.isOnSub=myElem(e).length>0



})

$(document).on('mousewheel',function(e){
  if(window.isOnSub){  
console.log(e.originalEvent.wheelDelta);      
    if( myElem(e).prop('scrollHeight')-myElem(e).scrollTop()<=myElem(e).height()&&(e.originalEvent.wheelDelta<0)){

      e.preventDefault()
    } 


}

})

replace '.slimScrollDiv' with the element selector you want to
prevent parent scroll while your mouse is on it

http://jsbin.com/cutube/1/edit?html,js,output

Ahmed Mahmoud
  • 1,479
  • 2
  • 12
  • 18
  • I don't understand, this will prevent not only scrolling of the parent but also scrolling of the child. Can you eddit my JSFiddle and show me how your solution works? Thanks – daniel.sedlacek Aug 27 '15 at 13:41
  • 1
    thanks for your comment please check my answer again I have edit it – Ahmed Mahmoud Aug 27 '15 at 14:45
  • I am sorry, I should have been more clear, I have seen similar solution but it depends on the need to specifically name/tag elements that you want to be scrollable. Such approach is error prone and unscalable. I have put this as a condition in my original question but forgot to mention in this question again. I made an edit to mention it now. – daniel.sedlacek Aug 28 '15 at 09:14