'Internet Explorer leaks click event after adding an overlay in a jQuery mousedown handler
In a mousedown
event-handler of a div another new div is created and appended to the body.
This new div has position:fixed
(can also be position:absolute
) and has 100% width and 100% height. Therefore it immediately covers the source div which triggered the mouse down event.
Now with the latest Google Chrome (v30), latest Firefox (v24), Opera v12.16 and even with a older Safari v5.1.1 (on Windows) after the mousedown event no click event gets fired on an event listener attached to the body.
Only Internet Explorer (both 9 and 10) does fire the click event on the body afterwards! Why? And how can this be prevented? Is this actually a bug in IE?
The HTML:
<div class="clickme">Click me</div>
The CSS:
.clickme {
background-color: #BBB;
}
.overlay {
position: fixed; /* or absolute */
left: 0;
top: 0;
height: 100%;
width: 100%;
background-color: #000;
}
The JavaScript:
$(document).on('click', function(event) {
console.log('body click');
});
$('.clickme').on('mousedown', function(event) {
console.log('div mousedown');
var mask = $('<div></div>');
mask.attr('class', 'overlay');
mask.appendTo('body');
});
Here is a the example with some additional comments: http://jsfiddle.net/Fh4sK/5/
After clicking the "Click me" div, only
div mousedown
should be written to the console, but in Internet Explorer it actually is
div mousedown
body click
I appreciate any help!
EDIT 1:
I found some resources describing the conditions when to trigger a click event:
http://www.quirksmode.org/dom/events/click.html:
"click - Fires when a mousedown and mouseup event occur on the same element."http://www.w3.org/TR/DOM-Level-3-Events/#events-mouseevent-event-order
"...in general should fire click and dblclick events when the event target of the associated mousedown and mouseup events is the same element with no mouseout or mouseleave events intervening, and should fire click and dblclick events on the nearest common ancestor when the event targets of the associated mousedown and mouseup events are different."
I'm not 100% sure what the "correct" behaviour now actually should be (maybe IE is the only browser which handles it right?). From the last sentence, it seems that it is correct to fire the click event on the body, because the body is the "nearest common ancestor" of both div elements. There are some other statements on the referenced w3.org page above, which describe the behaviour if an element gets removed, but again I'm not sure if this applies here, as no element gets removed, but covered by an other element.
EDIT 2:
@Evan opened a bug report asking Microsoft to drop the described behaviour: https://connect.microsoft.com/IE/feedback/details/809003/unexpected-click-event-triggered-when-the-elements-below-cursor-at-mousedown-and-mouseup-events-are-different
EDIT 3:
In addition to Internet Explorer, Google Chrome recently started to have the same behaviour: https://code.google.com/p/chromium/issues/detail?id=484655
Solution 1:[1]
I bumped into this issue too. I decided I'd make a jQuery plugin to solve this issue and put it on GitHub.
It's all here, feedback is welcome : https://github.com/louisameline/XClick
@mkurz : thanks for finding that W3 directive, you saved me a lot of time. @vitalets : I solved this issue because I use select2 like you (you led me to this topic). I'll fork the select2 repo and leave a message for the people interested in this.
I'll see if I can ask the Microsoft people to take a look at it and hopefully change that annoying click behavior.
Solution 2:[2]
I also struggled with such behavior. I've modified your fiddle to find out how all mouse events are triggered with dynamically created overlay:
So, when mousedown
handler of some element shows overlay on the same place where mousedown occured:
Chrome, FF:
mousedown
triggered on elementmouseup
triggered on overlayclick
does not trigger
IE:
mousedown
triggered on elementmouseup
triggered on overlayclick
triggered on BODY(!)
The same behavior if you hide mask in mousedown.
This issue can lead to weird things in IE with modals, masks, overlays etc..
Intresting thing: if you show overlay in mouseup
instead of mousedown
- everything works
The solution I found is to use mouseup
instead of mousedown
.
It can't be explained normally because both these events are triggered before click
.
In that case all mouse events are triggered on element:
mousedown
triggered on elementmouseup
triggered on elementclick
triggered on element
Hope this helps.
Solution 3:[3]
You could filter the document click by the target to exclude clicks on that div:
$(document).on('click', function(event) {
if(!$(event.target).hasClass('clickme')) {
console.log('body click');
}
});
Solution 4:[4]
If you want to stop bubbling of the click event, try this : (I don't have IE to test)
$(document).on('click', function(event) {
console.log('body click');
});
$('.clickme').on('mousedown', function(event) {
console.log('div mousedown');
});
$('.clickme').on('click', function(event) {
event.stopPropagation();
});
Click, mousedown and mouseup are differents events, independant. here is a similar question
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Louis Ameline |
Solution 2 | |
Solution 3 | rojoca |
Solution 4 | Community |