I have a bunch of divs positioned absolutely on top of each other. When I bind a click event to all of them, only the top div responds. How can I send the event to all divs under the cursor?
-
Is the error that you are not able to log to console the clicked message? – defau1t Jan 19 '13 at 12:26
-
@defau1t: He wants `clicked` appearing three times in the console when clicking once. – Amberlamps Jan 19 '13 at 12:26
-
http://jsfiddle.net/vA5WQ/23/ – TheOne Jan 19 '13 at 12:35
-
@Teemu: That's only related to nested elements, not to (potentially unrelated) elements positioned on top of each other. – Felix Kling Jan 19 '13 at 12:36
-
If only we were talking about Hypercard .... (anyone remember Hypercard?) – Beetroot-Beetroot Jan 19 '13 at 12:38
-
1This has been asked before, but I cannot find it right now. You can do the following: Hide the top element, get the next (underlying) element with `document.elementFromPoint` (where you pass the mouse coordinates to), repeat. – Felix Kling Jan 19 '13 at 12:49
-
Possible duplicate of http://stackoverflow.com/questions/3680429/click-through-a-div-to-underlying-elements – Exception Jan 19 '13 at 17:18
-
@FelixKling Yes this is a duplicate question. See my comment above – Exception Jan 19 '13 at 17:18
4 Answers
Taking FelixKling's suggestion to use document.elementFromPoint()
and Amberlamps's fiddle, and employing jQuery for the DOM interactions, I ended up with the following :
$divs = $("div").on('click.passThrough', function (e, ee) {
var $el = $(this).hide();
try {
console.log($el.text());//or console.log(...) or whatever
ee = ee || {
pageX: e.pageX,
pageY: e.pageY
};
var next = document.elementFromPoint(ee.pageX, ee.pageY);
next = (next.nodeType == 3) ? next.parentNode : next //Opera
$(next).trigger('click.passThrough', ee);
} catch (err) {
console.log("click.passThrough failed: " + err.message);
} finally {
$el.show();
}
});
try/catch/finally
is used to ensure elements are shown again, even if an error occurs.
Two mechanisms allow the click event to be passed through or not :
- attaching the handler to only selected elements (standard jQuery).
- namespacing the click event,
click.passThrough
analogous toevent.stopPropagation()
.
Separately or in combination, these mechanisms offer some flexibility in controlling the attachment and propagation of "passThrough" behaviour. For example, in the DEMO, try removing class p
from the "b" element and see how the propagation behaviour has changed.
As it stands, the code needs to be edited to get different application-level behaviour. A more generalized solution would :
- allow for programmatic attachment of app-specific behaviour
- allow for programmatic inhibition of "passThrough" propagation, analogous to
event.stopPropagation()
.
Both of these ambitions might be achieved by establishing a clickPassthrough
event in jQuery, with underlying "passThrough" behaviour, but more work would be involved to achieve that. Maybe someone would like to have a go.

- 18,022
- 3
- 37
- 44
-
-
If someone else has the same problem as me: `if ($(next).prop("tagName") === 'A') { window.location.href = $(next).attr('href'); }` – Richard Löwenström Nov 08 '14 at 13:18
This is not as easy as you might think. This is a solution that I came up with. I only tested it in Chrome and I did not use any framework.
The following snippet is just for add a click event to every div
in the document, that outputs its class name when triggered.
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++) {
divs[i].onclick = function() {
console.log("class clicked: " + this.className);
};
}
Attaching a click event to the body element so that every single click event is noticed by our script.
if(document.addEventListener) {
document.body.addEventListener("click", countDivs);
} else if(document.attachEvent) {
document.attachEvent("onclick", countDivs);
}
Iterate through all divs that you want to check (you might want to adjust here to your preferred range of divs). Generate their computed style and check whether the mouse coordinates are within the range of the div´s position plus its width and height. Do not trigger click event when the div is our source element because the click event has already been fired by then.
function countDivs(e) {
e = e || window.event;
for(var i = 0; i < divs.length; i++) {
var cStyle = window.getComputedStyle(divs[i]);
if(divs[i] !== e.target && e.pageX >= parseInt(cStyle.left) && e.pageX <= (parseInt(cStyle.left) + parseInt(cStyle.width)) && e.pageY >= parseInt(cStyle.top) && e.pageY <= (parseInt(cStyle.top) + parseInt(cStyle.height))) {
divs[i].click();
}
}
}
CSS:
.a, .b, .c {
position: absolute;
height: 100px;
width: 100px;
border: 1px #000 solid
}
.a {
top: 100px;
left: 100px;
}
.b {
top: 120px;
left: 120px;
}
.c {
top: 140px;
left: 140px;
}
HTML:
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
I also added a jsFiddle

- 39,180
- 5
- 43
- 53
-
How does your solution work? Could you also explain it instead of just posting code? – Felix Kling Jan 19 '13 at 12:55
-
1@FelixKling: I added some explanations. I think that is sufficient, isn´t it? – Amberlamps Jan 19 '13 at 13:00
-
Great! Just note that `e.srcElement` is IE only (Chrome added some of IEs features though). The official property for the originating element is `e.target`. – Felix Kling Jan 19 '13 at 13:04
-
-
Amberlamps & @FelixKling, as you won't be alerted, I thought I'd let you know that you both get a mention in my answer (above/below?). Ihre Gedanken (Ihr seid beide Deutsch nicht wahr)? – Beetroot-Beetroot Jan 19 '13 at 17:33
A simple way could be to use elementFromPoint():
var clicks = 0,cursorPosition={};
$('div').click(function (e) {
if(typeof cursorPosition.X === 'undefined') {
cursorPosition.X = e.pageX;
cursorPosition.Y = e.pageY;
}
clicks++;
e.stopPropagation();
$(this).addClass('hided');
var underELEM = document.elementFromPoint(cursorPosition.X, cursorPosition.Y);
if (underELEM.nodeName.toUpperCase() === "DIV") $(underELEM).click();
else {
$('#clicks').html("Clicks: " + clicks);
$('.hided').removeClass('hided');
clicks=0;
cursorPosition = {};
}
});

- 74,033
- 9
- 94
- 155
If you are stacking elements absolutely it may be simpler to stack them all in a positioned container, and handle the events from this parent. You can then manipulate its children without having to measure anything.

- 102,654
- 32
- 106
- 127