Open Bug 1084121 Opened 7 years ago Updated 3 years ago

Mouse wheel event is captured by iframe and not propagated - parent document should scroll if content inside IFRAME doesn't, and events should fire accordingly

Categories

(Core :: DOM: UI Events & Focus Handling, defect)

33 Branch
x86_64
Linux
defect
Not set
normal

Tracking

()

People

(Reporter: astrothayne, Unassigned)

Details

(Keywords: testcase)

User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36

Steps to reproduce:

I have a div in which I manually capture mousewheel events, and use that to scroll the div. Inside of this div, I have an embedded youtube video, in an iframe.  


Actual results:

While scrolling, if the mouse is over the iframe, scrolling no longer works, because all mouse events, including mouse wheel events, are captured by the iframe, and are not sent to the parent window.


Expected results:

The mouse wheel event should have been propagated to the parent window. This is the behavior in chrome and safari.

Since the iframe is on a different domain, there does not appear to be any feasible workaround for this.
Could you provide a testcase, please. But I think it's a dupe of bug 814977.
Flags: needinfo?(thayne)
Keywords: testcase-wanted
See http://pub.lucidpress.com/2b3571dd-21a1-4761-b0a2-ff413eed3a21/

scroll until the mouse is over the youtube video, and notice how it stops scrolling.
Flags: needinfo?(thayne)
Status: UNCONFIRMED → NEW
Component: Untriaged → Event Handling
Ever confirmed: true
Product: Firefox → Core
the iframe should get the scroll events, not anything outside it.

Also, the behavior is not defined in any spec.
The behavior in firefox produces a poor user experience is situations such as the example I supplied. The user doesn't necessarily know that the youtube video is an iframe, or even what an iframe is, and will be confused why scrolling sometimes doesn't work. 

My expectation would be that the mouse event would be fired inside the iframe, and unless propagation is stopped within the iframe the event would bubble up to the iframe element, and continue propagation from there.
This is basically by design. Your code should be completely unaware of what the user does inside an IFRAME (especially one from a different origin like YouTube).

Now, even in the cross-origin case browsers can choose to let scrolling affect the frame's ancestor if the frame itself doesn't scroll. This scrolling should happen without any events firing on the top document - see Chrome's behaviour if you scroll to the bottom of this IFRAME and keep scrolling:
http://jsfiddle.net/8cj0dofx/1/

But this bug, as written, is invalid.
Feel free to open a bug report saying "ancestor should scroll down (without events firing) if user scrolls above non-scrollable frame content" or something like that.
Status: NEW → RESOLVED
Closed: 7 years ago
Resolution: --- → INVALID
@Hallvord in your jsfiddle, chrome does fire the mousewheel event from inside the iframe if the iframe doesn't scroll.
It actually does. Why didn't I see that happen this morning??

Luckily for them, http://jsfiddle.net/8cj0dofx/2/ shows that they set event.target to the IFRAME element itself, so they avoid leaking some element from inside the IFRAME to the outer page's JS. 

That's sane and safe. Gecko should do the same thing.
Status: RESOLVED → REOPENED
Resolution: INVALID → ---
Status: REOPENED → NEW
Summary: Mouse wheel event is captured by iframe and not propogated. → Mouse wheel event is captured by iframe and not propagated - parent document should scroll if content inside IFRAME doesn't, and events should fire accordingly
That seems ideal to me.
Seems to me that the use of video on the web is just growing all the time - this problem appears to have been around quite some time. Whilst Chrome and Safari have sorted this some time back. I have been and ardent user of Firefox but maybe its time to bite the bullet and move over to chrome and hope that others do the same because it does not look like anything is going to happen anytime soon.
Just wanted to add that the frustration comes from the popularity of single page parallax websites that need to scroll - so video & Firefox = problem
Rick, can you explain the very unexpected behavior blink seems to have here. This is even
cross-domain leak, I'd say. Outer page can detect if the page in iframe doesn't do something.
Does blink detect if nothing in iframe is scrolled and does not have event listeners for wheel or what?
(If so, I consider it a (minor) security bug.)
Flags: needinfo?(rbyers)
I agree this behavior of blink is odd.  I filed https://code.google.com/p/chromium/issues/detail?id=564042 to discuss it there.  

Note that the 'wheel' event isn't really bubbling between iframes, a NEW DOM event get's dispatched to the parent frame when the wheel event goes unhandled in an iframe (i.e. the default action is to dispatch a similar event on the iframe element itself).

I'm not sure there's really a security issue here.  You could get almost the same information by occasionally and briefly adding a transparent div with a wheel handler over top of the frame.  For touchpads wheel events come at high frequency in batches, so you can infer there likely was an event that recently (or will soon) go to the iframe (same reason you can't assume the parent document can't track the mouse position while the cursor is over an iframe).

There's definitely a user and developer benefit to the way we've implemented this.  However we have some changes in mind (to unify our wheel and touchscreen scrolling code paths) that might make this more difficult to implement.  I'm not opposed to seeing if we can change this to match Firefox if we think the benefit is high and compat risk is low.  In general the scenarios that would depend on this functionality are already broken for touchscreen scrolling (touch events never propagate in this way), so I'm not sure it's really something we want to be supporting.
Flags: needinfo?(rbyers)
Sure, if the same event would propagate, and outer document would get access to the event (without security exceptions) that would be rather bad security bug. But I didn't have that in mind.
But is it a minor security issue even without that, since there is information leak about scrollability and/or wheel event handlers. I don't know how else on could get that information from
outer document.

wheel event having such default handling is surprising. The only tiny bit similar case in the platform is load event firing for the document in an iframe and then separate load event firing on the element itself.
Does blink have same kind of default handling also for some other events?
Flags: needinfo?(rbyers)
> Does blink have same kind of default handling also for some other events?

'wheel' (and so 'mousewheel') are the only cases I'm aware of like this.  It's a good point that 'load' is kind of similar.  Perhaps 'beforeunload' is even closer (if an iframe can cancel the event and so prevent its dispatch to other frames)?
Flags: needinfo?(rbyers)
well, there has been some talk to make beforeunload in iframe non-cancelable (given that beforeunload handling can be rather user-hostile).
'load' event is however a bit different to 'wheel' handling here, since no information about the inner page itself is exposed to the outer document.

And if we give 'wheel' this kind of privileged handling (over other events), why not mouse events? Or key events etc? or ...
FWIW; I've proposed changing this in Chrome. See our discussion here:

https://groups.google.com/a/chromium.org/d/msg/blink-dev/umMJkGAQ_P0/QNSrr_eeDwAJ
This is preventing carousel gallery with mix images/youtube/vimeo content and navigate by mousewheel option from working properly.
I understand the security concern, but is there any workaround for dealing with things like youtube/vimeo iframes inside of content that listens for mousewheel events to do some kind of custom scrolling?
(In reply to Thayne from comment #21)
> is there any workaround 

None I can think of unfortunately. It may be possible to use scroll events - but they have many drawbacks: if the page is shorter than the viewport you may not get scroll events at all, and if the page is longer than the viewport the scroll events you pick up might mean the user is really trying to scroll down, so changing those events into carousel navigation or something else custom would be very surprising behaviour. Finally, if you have written and tested your script on a tall screen and the user uses some different dimension that makes the content overflow you may end up catching scroll events in a way that makes below-the-fold content inaccessible.

The only thing you could do would be a postMessage()-based workaround (which would obviously require YouTube's collaboration and that of all other sites you might want to embed).

Actually - because of that and because of the undeniable fact that users won't know and should not have to care if some part of the page is inside an IFRAME, I find on further consideration that "propagating" the event to the parent document was a good choice that made it easier for web developers to write consistent UIs.
Component: Event Handling → User events and focus handling
You need to log in before you can comment on or make changes to this bug.