On eclecticgames.co.uk, the "drop-down" menu disappears when moving the mouse outside of the top-level item
Categories
(Web Compatibility :: Site Reports, defect, P1)
Tracking
(Webcompat Priority:P1, firefox-esr115 unaffected, firefox-esr128 disabled, firefox134 disabled, firefox135+ affected, firefox136+ affected)
Webcompat Priority | P1 |
People
(Reporter: babolivier, Unassigned, NeedInfo)
References
(Regression, )
Details
(6 keywords)
User Story
outreach-assignee:mbalfanz outreach-contact-date:2025-01-28 platform:windows,mac,linux impact:workflow-broken configuration:general affects:all branch:release diagnosis-team:dom user-impact-score:60
Attachments
(8 files)
On https://www.eclecticgames.co.uk/, users can place their cursor over the category names below the search bar to show a menu dropping down to offer specific categories to explore.
On Firefox (136.0a1 (2025-01-23) (64-bit)), moving the cursor away from the top-level category makes this menu disappear, even if the cursor is still on top of the menu itself.
On Chromium (132.0.6834.83), moving the cursor away from the top-level category does not change the menu's visibility as long as the cursor is still on top of the menu itself.
I've attached a screen recording showing the difference between Firefox and Chromium.
Comment 1•10 days ago
|
||
Regression window:
https://hg.mozilla.org/integration/autoland/pushloghtml?fromchange=16329a884928f3be3f38e8f77a3644ffc79fa879&tochange=2353c9757dd87aa8755d173379929a3f8f6f4235
Comment 2•10 days ago
|
||
Work around:
Set dom.events.mouse-pointer-boundary.keep-enter-targets-after-over-target-removed to false.
Updated•10 days ago
|
Comment 3•10 days ago
|
||
Hmm, the popup menu is not a child of the menu item in the menu bar. So, I've not understood why the mouse boundary event behavior change caused the regression.
According to the Inspector, there is no pointer boundary event listeners. So, this could be caused by edge cases of mouse boundary events which are not defined by the specs.
I'm not sure whether we should keep shipping the new boundary behavior because I'm not sure how much incompatible.
<nav>
<menu>
...
<li>
<a href="...">Boardgames & Cardgames</a>
<div style="display:none">...</div>
</li>
...
</menu>
</nav>
Note that the <div>
under the link is not the popup menu. The popup menu is in a sibling of the <nav>
.
When I move from above the link, "Boardgames & Cardgames", to the popup bellow the link, I got:
I/MouseBoundaryEvents NotifyMouseOver: the source event is eMouseMove (IsReal()=true)
I/MouseBoundaryEvents NotifyMouseOut: the source event is eMouseMove (IsReal()=true)
I/MouseBoundaryEvents Dispatching eMouseOut event to menu.nav.body.html.#document (2d96c00af70)
I/MouseBoundaryEvents Dispatching eMouseLeave event to menu.nav.body.html.#document (2d96c00af70) and its ancestors
I/MouseBoundaryEvents Dispatched
I/MouseBoundaryEvents Dispatching eMouseOver event to a.li.menu.nav.body.html.#document (2d96c00b7c0)
I/MouseBoundaryEvents Dispatching eMouseEnter event to a.li.menu.nav.body.html.#document (2d96c00b7c0) and its ancestors
I/MouseBoundaryEvents Dispatched "over" and "enter" events (the original "over" event target was in the document 2d96bc0d8
then,
I/MouseBoundaryEvents NotifyMouseOver: the source event is eMouseMove (IsReal()=true)
I/MouseBoundaryEvents NotifyMouseOut: the source event is eMouseMove (IsReal()=true)
I/MouseBoundaryEvents Dispatching eMouseOut event to a.li.menu.nav.body.html.#document (2d96c00b7c0)
I/MouseBoundaryEvents Dispatching eMouseLeave event to a.li.menu.nav.body.html.#document (2d96c00b7c0) and its ancestors
I/MouseBoundaryEvents Dispatched "out" and/or "leave" events
I/MouseBoundaryEvents Dispatching eMouseOver event to div.div.body.html.#document (2d972e37040)
I/MouseBoundaryEvents The dispatching "over" event target (2d972e37040) is removed
I/MouseBoundaryEvents The last "over" event target (2d972e37040) is removed and now the last deepest enter target becomes div.body.html.#document(2d96c098af0)
I/MouseBoundaryEvents Dispatching eMouseEnter event to div (2d972e37040) and its ancestors
I/MouseBoundaryEvents Dispatched "over" and "enter" events (the original "over" event target was in the document 0, and now in 2d96bc0d800)
D/MouseBoundaryEvents Forgetting the last "over" event target (2d972cd75b0) because it is not reconnected under the deepest enter event target (2d96c098af0)
I'm not sure the last mouseover
target <div>
is which one. However, it's removed from the DOM by a mouseover
event listener. Then, it's not reconnected immediately. So, the website touches the black box of mouse boundary events.
The popup is:
<div class="nav-menu nav-menu_xxx">
<div class="nav-menuCol">
<a class="nav-link ...">...</a>
...
</div>
<div class="nav-menuCol">
<a class="nav-link ...">...</a>
...
</div>
</div>
When I move over the popup, mouseover
is fired on the <div class="nav-menuCol">
and it's removed.
If I disable the pref, I got:
I/MouseBoundaryEvents NotifyMouseOver: the source event is eMouseMove (IsReal()=true)
I/MouseBoundaryEvents NotifyMouseOut: the source event is eMouseMove (IsReal()=true)
I/MouseBoundaryEvents Dispatching eMouseOut event to a[class="nav-topLink is-active"].li[class="nav-topItem"].menu[class="nav-topBar nav-visible"].nav[class="nav"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (13ba9a0b7c0)
I/MouseBoundaryEvents Dispatching eMouseLeave event to a[class="nav-topLink is-active"].li[class="nav-topItem"].menu[class="nav-topBar nav-visible"].nav[class="nav"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (13ba9a0b7c0) and its ancestors
I/MouseBoundaryEvents Dispatched "out" and/or "leave" events
I/MouseBoundaryEvents Dispatching eMouseOver event to div[class="nav-menuCol"].div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (13bb031f0d0)
I/MouseBoundaryEvents The last "over" event target (13bb031f0d0) is removed
I/MouseBoundaryEvents Dispatching eMouseEnter event to div[class="nav-menuCol"] (13bb031f0d0) and its ancestors
I/MouseBoundaryEvents Dispatched "over" and "enter" events (the original "over" event target was in the document 0, and now in 13ba7ad9800)
Comment 8•9 days ago
•
|
||
Ah, okay, next one chunk may be important.
Within the new behavior:
I/MouseBoundaryEvents NotifyMouseOver: the source event is eMouseMove (IsReal()=false)
I/MouseBoundaryEvents NotifyMouseOut: the source event is eMouseMove (IsReal()=false)
I/MouseBoundaryEvents Dispatching eMouseLeave event to div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (193d61a0670) and its ancestors
I/MouseBoundaryEvents Dispatched "out" and/or "leave" events
I/MouseBoundaryEvents Dispatching eMouseOver event to div[class="nav-menuCol"].div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (193dc5460d0)
I/MouseBoundaryEvents Dispatching eMouseEnter event to div[class="nav-menuCol"].div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (193dc5460d0) and its ancestors
I/MouseBoundaryEvents Dispatched "over" and "enter" events (the original "over" event target was in the document 193d43e1800, and now in 193d43e1800)
Within the legacy behavior:
I/MouseBoundaryEvents NotifyMouseOver: the source event is eMouseMove (IsReal()=false)
I/MouseBoundaryEvents Dispatching eMouseOver event to div[class="nav-menuCol"].div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (13ba9af04c0)
I/MouseBoundaryEvents Dispatching eMouseEnter event to div[class="nav-menuCol"].div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (13ba9af04c0) and its ancestors
I/MouseBoundaryEvents Dispatched "over" and "enter" events (the original "over" event target was in the document 13ba7ad9800, and now in 13ba7ad9800)
I/MouseBoundaryEvents The last "over" event target (13ba9af04c0) is removed
I/MouseBoundaryEvents NotifyMouseOver: the source event is eMouseMove (IsReal()=false)
I/MouseBoundaryEvents Dispatching eMouseOver event to div[class="nav-menuCol"].div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (13bb0334dc0)
I/MouseBoundaryEvents Dispatching eMouseEnter event to div[class="nav-menuCol"].div[class="nav-menu nav-menu_3003279 is-visible"].body[class="l-fullHeight pg-home"].html[class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage no-websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients no-cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers no-applicationcache svg inlinesvg smil svgclippaths wf-montserrat-n4-active wf-active"].#document (13bb0334dc0) and its ancestors
I/MouseBoundaryEvents Dispatched "over" and "enter" events (the original "over" event target was in the document 13ba7ad9800, and now in 13ba7ad9800)
So, it seems that the mouseleave
on <div class="nav-menu">
causes the issue.
Oh, but there is no mouseleave
event listener...
I still don't understand what's going on, and it's hard to debug the website from C++ side due to mouse event boundary events. It'd be really helpful if somebody would create a minimized testcase.
Note that I wrote some tests to check the behavior on Chrome, but their events also odd. So, that makes me harder to debug the website too.
Comment 11•9 days ago
|
||
(In reply to Masayuki Nakano [:masayuki] (he/him)(JST, +0900) from comment #4)
I'm not sure whether we should keep shipping the new boundary behavior because I'm not sure how much incompatible.
We're building the Fx135 RC on Monday. Please let me know ASAP what we want to do here.
Updated•9 days ago
|
I chatted with smaug, the change should be backed out from the beta channel, and I think that it should be backed out from m-c too because it'll be merged to the next beta soon.
RyanVM: Could you back it out from both beta and m-c?
(And keep open this bug since it's reproducible on Nightly and early beta builds even after back it out.)
Comment 14•8 days ago
•
|
||
@masayuki, @smaug, @hsin-yi -- How will backing out the change impact Firefox's final Interop-2024 score? How bad is the possible breakage you're worried about if this ships? Are there any reasonable alternatives to backing out?
IIUC we don't fully understand yet why this site is showing a problem, and we don't know if the problem is unique to this site or if other sites are affected. If other sites are affected, it may be minimal. Since this behavior is all behind a pref, we could pref it off after it goes to Release via Nimbus if there are significant problems. Reading this bug report, I'm uncertain that this problem rises to the level of significant. If you disagree and have additional information that makes you believe this will cause significant problems, please weigh in. Thanks!
Comment 15•8 days ago
•
|
||
@jgraham - How bad of a webcompat problem is this if we ship vs backout the support for the new mouse/pointer boundary behavior (which is the Pointer and Mouse Events focus area in Interop-2024)? You rated this bug as a P3, which is normally a bug we can live with for a while.
Also, what sites are likely fixed or improved by shipping the new mouse/pointer boundary behavior?
IIUC we don't fully understand yet why this site is showing a problem, and we don't know if the problem is unique to this site or if other sites are affected.
Yes, debugging from C++ side, I've not found the root cause from the dispatching events. So, it might be caused by the website using different paths for Firefox and the others.
Are there any reasonable alternatives to backing out?
We could back out only about mouse boundary events, but it might cause other issues if websites use both point and mouse boundary events. (Anyway, this requires to write a patch to split the pref like this, however, anyway the score will have damage because the scope includes mouse boundary events.
Reading this bug report, I'm uncertain that this problem rises to the level of significant.
At least for the website, this is serious because of breaking the main UI of their navigation. However, I'm still not sure whether it's our side issue or theirs.
NOTE: Once we back the patch out, we start failing in following Interop2024 scope tests:
pointerevent_after_target_appended.html?mouse
(3)pointerevent_after_target_removed.html?mouse
(4)synthetic-mouse-enter-leave-over-out-button-state-after-target-removed.tentative.html
(4)
Comment 17•7 days ago
•
|
||
As I expected after looking at the patches, it is the code around https://phabricator.services.mozilla.com/D199695 which caused the regression.
Not that patch itself, after all.
This line
https://searchfox.org/mozilla-central/rev/a965e3c683ecc035dee1de72bd33a8d91b1203ed/dom/events/EventStateManager.cpp#6643
more precisely
https://searchfox.org/mozilla-central/rev/a965e3c683ecc035dee1de72bd33a8d91b1203ed/dom/events/EventStateManager.cpp#545
Comment 18•7 days ago
|
||
Thanks, Masayuki and Smaug. I'm going to ask the webcompat team in slack and matrix to deep-dive on this so we can figure out why Firefox is having problems on this site and Chrome isn't. (Is it bad site code? Is it an error on our side? Is it timing related and just "luck" that it works in Chrome?) Once we know that, we should have a much better idea of what the best next steps are. If you can please be available in #webcompat on slack and "Web Compatiblity" on matrix during your normal business hours, that would be very helpful here. Thanks.
Comment 19•7 days ago
|
||
Hmm, so dom.events.mouse-pointer-boundary.keep-enter-targets-after-over-target-removed=false
would "fix" this, is that less risk than just backing out?
Comment 20•7 days ago
|
||
There are a lot of mouse{enter,leave} listeners, fwiw. The relevant ones seem to be mouse{enter,leave} in this section of the code. It seems they use setTimeout(20) in some places, setTimeout(0) in others, and sync toggle() calls...
Comment 21•7 days ago
|
||
One tricky thing is that those listeners end up being mouse{over,out}
listeners because of jquery...
Comment 22•7 days ago
|
||
(Relevant link for the above is https://github.com/jquery/jquery/blob/098591e6fd3222e64b59af92c8849f5d8963d43c/src/event.js#L811)
So the page receives the mouseover
on the menu, the page calls toggle()
again, which calls showMenu
(but async since it's a _.debounce(..)
d function). We're open, so we call calcLayout()
. this replaces the whole contents of the menu (that's the this.menu.html(this.cachedCalcs[e].html))
), and that ends up firing a mouseout
, which closes the menu, without a corresponding mouseover
again.
So yeah I suspect this kinda depends on the timing of the synthetic mouse events and such, but I don't see why we'd fire a mouseout
on the menu as a consequence of those mutations to begin with, and I don't see why we wouldn't fire another mouseover
if we did... Masayuki, does the above help somehow?
Comment 23•7 days ago
|
||
In case someone finds it useful to crib from.
Comment 24•7 days ago
|
||
(In reply to Emilio Cobos Álvarez (:emilio) from comment #19)
Hmm, so
dom.events.mouse-pointer-boundary.keep-enter-targets-after-over-target-removed=false
would "fix" this, is that less risk than just backing out?
That is what the backout we've been pondering means, backing out bug 1938528
Comment 25•7 days ago
|
||
This specific broken site probably isn't a serious webcompat problem; given the site is outside the local/global top 100k and it doesn't affect Android, if we did the triage it would get at most 80 points if we considered the breakage to be a broken workflow, 30 if we considered it a broken feature. Given that you can still access all the functionality by clicking on the main menu item and then using the filters on the subsequent pages it's arguably more like a broken feature, so I"d be inclined to triage at the lower severity.
So I think the main question here is not about this one site (although it's a regression); if necessary I would imagine there's a good chance we could figure out an intervention to fix this specific case. It's whether this is a early warning of more significant problems with the patch / our new behaviour. To figure that out we'll need a proper root cause. I can take a look at this some more tomorrow.
Comment 26•7 days ago
|
||
FWIW, with devtools "Pick an element from the page" the menu keeps opening, though I am totally unsure what devtools does, it might be a chance to use webcompat intervention in the same manner what devtools does.
(Sorry, I'm on a PTO today, I'll check it tomorrow.)
(In reply to Emilio Cobos Álvarez (:emilio) from comment #22)
So yeah I suspect this kinda depends on the timing of the synthetic mouse events and such, but I don't see why we'd fire a
mouseout
on the menu as a consequence of those mutations to begin with, and I don't see why we wouldn't fire anothermouseover
if we did... Masayuki, does the above help somehow?
Thank you for the investigation. I guess that the temporarily removed mouseover
target is reconnected again in a duration which we think enough short. Therefore, we may not treat it as disconnected to fix bug 1886012 (the patch).
Comment 29•7 days ago
•
|
||
So, accoding to Emilio's investigation, we could fix this if we dispatch eMouseOver
again when we restore the temporary removed target. However, it's potentilly risky change because it might cause an infinite loop.
Comment 30•6 days ago
|
||
Here is a slightly minified and pretty-printed testcase; note that jquery isn't pretty-printed because that somehow seems to break it.
(In reply to Masayuki Nakano [:masayuki] (he/him)(JST, +0900) from comment #29)
So, accoding to Emilio's investigation, we could fix this if we dispatch
eMouseOver
again when we restore the temporary removed target. However, it's potentilly risky change because it might cause an infinite loop.
I tried to do that, but it does not work on the web site, it may be not enough or I'm just misunderstanding something.
Comment 32•6 days ago
|
||
I still don't understand why were sending the mouseout to the menu. The menu is not getting disconnected aiui, just has all their children replaced
(In reply to Emilio Cobos Álvarez (:emilio) from comment #32)
I still don't understand why were sending the mouseout to the menu. The menu is not getting disconnected aiui, just has all their children replaced
Do you mean that "the menu" is the <a>
in the menu bar, not in the popup? The popup is not a child of the <a>
and anyway, when the element underneath the cursor is changed, mouseout
needs to be dispatched.
Ah, the contnt of the popup is replaced with same HTML but different nodes. mouseout
should be fired if and only if the last mouseover
target is connected and hann't been removed except temporarily. Well, but I've not gotten that which mouseout
is odd.
Comment 35•6 days ago
|
||
The bug is marked as tracked for firefox135 (beta) and tracked for firefox136 (nightly). We have limited time to fix this, the soft freeze is in 3 days. However, the bug still isn't assigned.
:ksenia, could you please find an assignee for this tracked bug? Given that it is a regression and we know the cause, we could also simply backout the regressor. If you disagree with the tracking decision, please talk with the release managers.
For more information, please visit BugBot documentation.
Comment 36•6 days ago
|
||
(In reply to Emilio Cobos Álvarez (:emilio) from comment #32)
I still don't understand why were sending the mouseout to the menu. The menu is not getting disconnected aiui, just has all their children replaced
I don't think that event is the issue: it is sent after the menu is closed (and I think it is sent because the menu was closed).
The real issue seems to be a mousemove handler on the document that decides to close the menu.
Comment 37•6 days ago
|
||
This breakpoint is hit in Firefox but not in Chrome.
Comment 38•6 days ago
•
|
||
I've found a key difference between Nightly and Stable: there is an event that triggers a handler in Stable but not in Nightly.
I've added logpoints to the boundary event handlers attached to this.menu
and this.btn
and a logpoint to the mousemove handler when it decides the menu should be closed (because it thinks the mouse is outside of it). And I've added event listener logpoints to mouseover, mouseenter and mouseout.
Note that in both cases the jQuery handler is called but in Nightly, jQuery doesn't call the app's handler, so we'll have to figure out what leads to the different jQuery behavior.
Comment 39•6 days ago
|
||
This is what I see in Stable.
Comment 40•6 days ago
|
||
This is what I see in Nightly.
Comment 41•6 days ago
|
||
The mousemove handler sets this.hoverBtn
and this.hoverMenu
to false
and schedules a call to showMenu()
. Before showMenu()
is called, a mouseover event is handled by this.menu
in Stable, which sets this.hoverMenu
to a truthy value. When showMenu()
is called it decides whether to show or hide the menu based on this.hoverBtn
and this.hoverMenu
- that's why the menu is closed in Nightly (where this.hoverMenu
is still false
) but not in Stable.
Comment 42•6 days ago
|
||
Furthermore there's a difference between Firefox and Chrome: in Firefox when the mouse moves from the menu button to the menu, a mousemove event is fired with the document as its target but I never see that target in mousemove events in Chrome.
Comment 43•6 days ago
|
||
We've decided to build RC1 with things left as-is with the option for an RC2 respin later this week still on the table pending further debugging. LMK if that's the route we decide to go.
Updated•6 days ago
|
Comment 44•6 days ago
•
|
||
(In reply to Holger Benl from comment #42)
Furthermore there's a difference between Firefox and Chrome: in Firefox when the mouse moves from the menu button to the menu, a mousemove event is fired with the document as its target but I never see that target in mousemove events in Chrome.
When mouse moves from menu button to menu, a timeout task is scheduled in mouseout
event listener of menu button in https://www.eclecticgames.co.uk/js/main.js?v=1.1140
.bind(this)),
this.btn.on("mouseleave", function(t) {
this.hoverBtn = !1,
setTimeout(this.toggle.bind(this), 20)
}
I log the event and set a breakpoint on toggle
method, and found the timeout handler runs in different timing,
Nightly with dom.events.mouse-pointer-boundary.keep-enter-targets-after-over-target-removed
=true
:
mouseout <a class="nav-topLink is-active" href="c/boardgames-cardgames" ir-navsubbtn="">
mouseover <div class="nav-menuCol"> // <==== This set this.hoverMenu
to true
mousemove HTMLDocument https://www.eclecticgames.co.uk/c/boardgames-cardgames // <==== This set this.hoverMenu
to false
/// <==== timeout handler runs here, which closes the menu due to this.hoverMenu
is false
.
mouseover <div class="nav-menuCol">
mousemove <div class="nav-menuCol">
mousemove <div class="nav-menuCol">
mousemove <div class="nav-menuCol">
mouseout <div class="nav-menuCol">
Nightly with dom.events.mouse-pointer-boundary.keep-enter-targets-after-over-target-removed
=false
:
mouseout <a class="nav-topLink is-active" href="c/boardgames-cardgames" ir-navsubbtn="">
mouseover <div class="nav-menuCol">. // <==== This set this.hoverMenu
to true
mousemove HTMLDocument https://www.eclecticgames.co.uk/c/boardgames-cardgames. // <=== This set this.hoverMenu
to false
mouseover <div class="nav-menuCol"> // <=== This set this.hoverMenu
to true
again
/// <==== timeout handler runs here
mousemove <div class="nav-menuCol">
mouseover <div class="nav-menuCol">
Chrome:
mouseout <a class="nav-topLink is-active" href="c/boardgames-cardgames" ir-navsubbtn>Boardgames & Cardgames</a>
mouseover <div class="nav-menuCol">…</div> // <==== This set this.hoverMenu
to true
~mouseover <div class="nav-menuCol">…</div>~
//// <==== timeout handler runs here
mousemove <div class="nav-menuCol">…</div>
mouseover <div class="nav-menuCol">…</div>
Edit: It turns out not related to timing but the app's handler doesn't run for the mouseover
after the mousemove HTMLDocument
. Please see comment# 46.
Comment 45•6 days ago
|
||
Thanks, Edgar -- what happens if we change the timeout to be longer? Does the problem appear to go away?
Comment 46•6 days ago
|
||
Unlike Edgar, I keep seeing a mouseover <div class="nav-menuCol">
after themousemove HTMLDocument
and before the timeout handler runs in both Nightly and Stable / Nightly with dom.events.mouse-pointer-boundary.keep-enter-targets-after-over-target-removed=false
.
The difference is that in Nightly the mouseover has a relatedTarget
whereas in Stable and Nightly with dom.events.mouse-pointer-boundary.keep-enter-targets-after-over-target-removed=false
relatedTarget
is null
and for some reason jQuery only dispatches the event to the app's handler if relatedTarget
is null
.
It seems to me that the new behavior is correct and Chrome also sets relatedTarget
for these events. But Chrome doesn't have an issue because it doesn't fire the mousemove HTMLDocument
event.
Comment 47•6 days ago
|
||
Thanks Holger - should the mousemove HTMLDocument event be sent? I.e. does Chrome work because it has a bug, and this page is dependent on that bug?
I noticed on the company that builds this package for these sites that their dropdown (which appears similar) does NOT hit this bug; is it possible they updated the package/library but it hasn't been incorporated into already-existing clients? I imagine the best way to find out would be to ask them, though in theory we could find it from examining the code on their page - https://www.intelligentretail.com/
Comment 48•6 days ago
|
||
I looked at their site, and it does appear to use the same menu system. I didn't try to compare code between the two beyond noticing the similarities of how it's set up.
Comment 49•6 days ago
|
||
Chrome also has relatedTarget
set but to a different element: in Firefox it is set to the <div class="nav-menu">
that contains the target <div class="nav-menuCol">
but in Chrome it is set to another <div class="nav-menuCol">
that is disconnected from the DOM (but looks like the the target <div class="nav-menuCol">
, so apparently it's an old copy of that element).
jQuery doesn't dispatch this event if the relatedTarget
is identical to the element on which the handler is registered, which is the case here (in Firefox).
Comment 50•6 days ago
|
||
(In reply to Randell Jesup [:jesup] (needinfo me) from comment #47)
Thanks Holger - should the mousemove HTMLDocument event be sent? I.e. does Chrome work because it has a bug, and this page is dependent on that bug?
I don't know, I'm not familiar enough with the spec.
I noticed on the company that builds this package for these sites that their dropdown (which appears similar) does NOT hit this bug; is it possible they updated the package/library but it hasn't been incorporated into already-existing clients? I imagine the best way to find out would be to ask them, though in theory we could find it from examining the code on their page - https://www.intelligentretail.com/
I'll try to compare their code tomorrow.
Comment 51•6 days ago
|
||
Oh, Holger is right, the app's handler isn't run for mouseover
after the mousemove HTMLDocument
, I thought the event is not yet dispatched. So the change the timeout to be longer doesn't help.
Comment 52•6 days ago
|
||
This test is an extension of the one in comment #23 and should simulate the page behavior.
Thank you very much, Holger and Edgar!!! I'll try to understand what's going on.
Interesting, Chrome dispatches mouseover
on replaced element if user moves the cursor again.
Additionally, when mouseover
makes the target disconnected, they stops dispatching the source mousemove
event. However, we do it on the Document
node.
Okay, it fixes the root cause if I makes us stop dispatching the source event of mouse/pointer boundary events (i.e., the mousemove
event on the Document
in the case). I'll run automated tests with the patch, but I think that this is pretty risky change especially for RC builds. So, anyway the patch is not available in the 135 branch.
Comment 56•5 days ago
|
||
@masayuki - Is that change in behavior (to more closely match Chrome's behavior) within the spec? What is the risk of doing this?
Oh, it seems that Chromium developers want to change something around mousemove
event dispatcher.
I wrote WPT for bug 1944191. However, Chrome Canary dispatches mousemove
on connected ancestor of removed/replaced mouseover
target. However, with running Chrome Canary with --no-enable-experimental
, they dispatch mousemove
on the disconnected mouseover
target. Therefore, it does not run mousemove
event listener on the Document
node.
Comment 58•5 days ago
•
|
||
(In reply to Randell Jesup [:jesup] (needinfo me) from comment #56)
@masayuki - Is that change in behavior (to more closely match Chrome's behavior) within the spec? What is the risk of doing this?
No, there is no definition. If we can emulate Chrome's behavior completely, the risk is not so high, but it's difficult because Chrome's mouse boundary behavior is not so clear to me and feels odd to me in some cases.
EDIT: See comment 60.
(I think that the website should not use mousemove
to hide the menu due to the stable state of mousemove
definition of such edge case.)
(In reply to Masayuki Nakano [:masayuki] (he/him)(JST, +0900) from comment #58)
(In reply to Randell Jesup [:jesup] (needinfo me) from comment #56)
@masayuki - Is that change in behavior (to more closely match Chrome's behavior) within the spec? What is the risk of doing this?
No, there is no definition. If we can emulate Chrome's behavior completely, the risk is not so high, but it's difficult because Chrome's mouse boundary behavior is not so clear to me and feels odd to me in some cases.
Oh, I found this paragraph in "3.4.4. Mouse Event Order":
If the event target (e.g. the target element) is removed from the DOM during the mouse events sequence, the remaining events of the sequence MUST NOT be fired on that element.
However, I'm not 100% sure whether this covers the mouse boundary events, and this does not match with the experimental behavior of Chrome Canary.
Er, if this means that mousemove
event should be fired on new target in the composed tree rather than the disconnected mouseover
target, Chrome Canary's new behavior matches with this paragraph.
If the experimental feature is disabled, Chromium considers the mousemove
event target with the composedPath
of preceding pointermove
. However, if it's enabled, Chromium considers the target from the deepest mouseenter
event target in the tree.
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/input/pointer_event_manager.cc;l=1085-1088;drc=27d34700b83f381c62e3a348de2e6dfdc08364b8
I don't understand the reason why this makes Chrome Canary stop dispatching mousemove
after replacing the mouseover
target.
https://jsfiddle.net/d_toybox/3tsd72rc/4/
Comment 63•5 days ago
|
||
so, to summarize:
- Chrome's current behavior doesn't match the spec. Canary's new experimental behavior matches a possible interpretation of the spec, but the spec isn't 100% clear here.
- Our behavior doesn't match the spec, but in a different manner than Chrome
- The website is relying on a non-spec behavior of Chrome
Are those correct?
(In reply to Randell Jesup [:jesup] (needinfo me) from comment #63)
so, to summarize:
- Chrome's current behavior doesn't match the spec. Canary's new experimental behavior matches a possible interpretation of the spec, but the spec isn't 100% clear here.
Right.
- Our behavior doesn't match the spec, but in a different manner than Chrome
Right.
- The website is relying on a non-spec behavior of Chrome
It seems that both yes and no. Even if I enable "Boundary Event Dispatch Tracks Node Removal" experimental feature of Chrome Canary (that should dispatch mousemove
after , the menu works on Chrome Canary. So, there is another compatible issue at least, but I don't know the details.
Okay, I got the another cause. If we stop synthesizing mouseover
in the next animation frame, the website works.
According to attachment 9462063 [details], when we dispatch mouseover
on menu
, it tries to show the popup. Then, we dispatch mousemove
on the document node which cases setting hoverMenu
to false
. At this point, we store the deepest mouseenter
target is the menu
. Then, we dispatch mouseover
event on the new popup. Then, the mouseover
's relatedTarget
is set to menu
. Therefore, mouseover
event listener of menu
does nothing due to skipEvent(menu, e)
. Finally, toggle
may be fired by setTimeout(toggle, 20)
in mouseout
event listener of link
and close the menu due to hoverMenu
== false
. So, the our bug is, we set wrong relatedTarget
.
Hmm... I'm really confused again. Once I enable the experimental feature on Chrome Canary, the website works but starting to fail in attachment 9462063 [details].
I mean, I cannot write a reasonable WPT for bug 1944212. Perhaps, we haven't reached the root cause yet.
Wow, I realized that Chrome Canary works differently if I modified attachment 9462063 [details]:
<nav id="menu"><div class="contents">something<br>something</div></nav>
to:
<nav id="menu">
<div class="contents">something<br>something</div>
</nav>
Setting innerHTML
difference might cause changing the mouseover
targetting on Chrome...
Ah,
$(document).on(
'mousemove',
function (t) {
IR.breakpoint.value >= this.breakpoint &&
(this.hoverBtn || this.hoverMenu) &&
$(t.target).closest(this.menu).length < 1 &&
$(t.target).closest(this.btn).length < 1 &&
(this.hoverBtn = !1, this.hoverMenu = !1, this.toggle())
}.bind(this)
$(t.target).closest(this.menu).length < 1
must work for Chrome because their mousemove
is fired on parent of the replaced element, i.e., menu
.
Comment 70•5 days ago
|
||
(In reply to Randell Jesup [:jesup] (needinfo me) from comment #47)
I noticed on the company that builds this package for these sites that their dropdown (which appears similar) does NOT hit this bug;
I've looked at the site: the code is almost identical (the line numbers in the pretty-printed files are off a little so there seems to be a small difference) and the menu sometimes works and sometimes doesn't (showing the same issue as eclecticgames.co.uk). I've also seen the menu work sporadically on eclecticgames.co.uk but on intelligentretail.com it works a lot more often. To reproduce the issue on intelligentretail.com move the mouse slowly from the button to the menu.
So there are other sites having the same issue, confirming the high priority.
Comment 71•5 days ago
|
||
A question for the people doing diagnosis: is there a simple change we could suggest to the site authors that would fix this issue (without regressing Chrome or other browsers)? It seems like their code is racy and poking at underdefined parts of the platform, so irrespective of whether we can implement behaviour that aligns with Chrome/others, ultimately the current situation is best fixed by the site making changes.
I hope, this change has no problem.
Comment 73•5 days ago
•
|
||
(In reply to James Graham [:jgraham] from comment #71)
A question for the people doing diagnosis: is there a simple change we could suggest to the site authors that would fix this issue (without regressing Chrome or other browsers)? It seems like their code is racy and poking at underdefined parts of the platform, so irrespective of whether we can implement behaviour that aligns with Chrome/others, ultimately the current situation is best fixed by the site making changes.
I think the most straightforward fix would be to ignore mousemove events whose target is the document in the handler that closes the menu when the mouse is outside of it. I've tried this fix (adding t.target.nodeType !== 9
to the condition in the handler) and it fixed the issue for me.
Note that there seems to be another issue with the same symptoms on intelligentretail.com: the menu also closes sometimes when the mouse moves from the button over it but on that site it also happens in Firefox Stable and Chrome and my proposed fix doesn't fix the issue there.
Updated•5 days ago
|
Updated•4 days ago
|
Updated•4 days ago
|
Updated•2 days ago
|
Description
•