Pass mouse events through absolutely-positioned element
Solution 1
pointer-events: none;
Is a CSS property that makes events "pass through" the HTML-element to which the property is applied. It makes the event occur on the element "below".
See for details: https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
It is supported by almost all browsers, including IE11; global support was ~98.2% in 05/'21): http://caniuse.com/#feat=pointer-events (thanks to @s4y for providing the link in the comments).
Solution 2
If all you need is mousedown, you may be able to make do with the document.elementFromPoint
method, by:
- removing the top layer on mousedown,
- passing the
x
andy
coordinates from the event to thedocument.elementFromPoint
method to get the element underneath, and then - restoring the top layer.
Solution 3
Also nice to know...
Pointer-events can be disabled for a parent element (probably transparent div) and yet be enabled for child elements.
This is helpful if you work with multiple overlapping div layers, where you want to be able click the child elements of any layer. For this all parenting divs get pointer-events: none
and click-children get pointer-events reenabled by pointer-events: all
.parent {
pointer-events:none;
}
.child {
pointer-events:all;
}
<div class="some-container">
<ul class="layer-0 parent">
<li class="click-me child"></li>
<li class="click-me child"></li>
</ul>
<ul class="layer-1 parent">
<li class="click-me-also child"></li>
<li class="click-me-also child"></li>
</ul>
</div>
Solution 4
The reason you are not receiving the event is because the absolutely positioned element is not a child of the element you are wanting to "click" (blue div). The cleanest way I can think of is to put the absolute element as a child of the one you want clicked, but I'm assuming you can't do that or you wouldn't have posted this question here :)
Another option would be to register a click event handler for the absolute element and call the click handler for the blue div, causing them both to flash.
Due to the way events bubble up through the DOM I'm not sure there is a simpler answer for you, but I'm very curious if anyone else has any tricks I don't know about!
Solution 5
There is a javascript version available which manually redirects events from one div to another.
I cleaned it up and made it into a jQuery plugin.
Here's the Github repository: https://github.com/BaronVonSmeaton/jquery.forwardevents
Unfortunately, the purpose I was using it for - overlaying a mask over Google Maps did not capture click and drag events, and the mouse cursor does not change which degrades the user experience enough that I just decided to hide the mask under IE and Opera - the two browsers which dont support pointer events.
s4y
Enthusiastic software engineer working on Chrome for Mac at Google. Original content is dedicated to the public domain (CC0). Do with it as you see fit.
Updated on July 30, 2022Comments
-
s4y almost 2 years
I'm attempting to capture mouse events on an element with another absolutely-positioned element on top of it.
Right now, events on the absolutely-positioned element hit it and bubble up to its parent, but I want it to be "transparent" to these mouse events and forward them on to whatever is behind it. How should I implement this?
-
s4y almost 15 yearsThanks for the response, Loktar. Unfortunately, on the real page I'm not going to know what's underneath the absolutely-positioned element, and there may be more than one possible target. The only workaround I can think of is grabbing the mouse coordinates and comparing them against possible targets to see if they intersect. That would be just plain nasty.
-
s4y almost 13 yearsThanks! This is a perfect solution for modern (and non-IE) browsers. At the time this question was posted, I don’t think
pointer-events
existed! I may switch the accepted answer over to this one at some point. -
Nathan about 12 yearsMore wordy explanation here: vinylfox.com/forwarding-mouse-events-through-layers
-
Dan Abramov about 12 yearsWoah, this just saved me hours.
-
s4y over 11 yearsI just switched the accepted answer to this one. Support for
pointer-events
still isn’t super awesome, but it’s getting better. For a more-compatible option, go with @JedSchmidt’s answer. -
jpeltoniemi about 11 yearsAwesome, I didn't know that method even existed! It can be also be used quite easily to get all elements under cursor using a while loop to get the topmost element and then hide it in order to find the next one. Grab my version here: gist.github.com/Pichan/5498404
-
Mohammed A. Al Jama about 10 yearsThanks, I never knew this actually exists. it saved me hours
-
Eric Rowell about 10 yearsAwesome! A note on browser support... curse you IE! foiled again. One day IE, one day.
-
Impossibear over 9 yearsThe problem with this workaround is that it doesn't work with zooming the page. For mobile devices or desktop browsers zoomed in X Y coordinates no longer mean anything, and there is no clear way to calculate zoom. i believe for pinch zooming it's actually impossible.
-
netpoetica over 9 yearsIs there an equivalent for Touch events? touch-events: none; or the like?
-
Juan Cortés almost 9 yearsAwesome, right after the high of discovering
pointer-events:none
and the imminent let-down of having children nodes affected, you save the day :) -
Allisone almost 9 years;) very glad about that
-
Shelvacu over 8 years@netpoetica I believe touch events count as pointer events, but I may be wrong. Feel free to ask a separate question and link to this one.
-
swelet over 7 yearsNever have gone to consult Google about anything to find an answer as simple as this. Simply awesome.
-
RaisinBranCrunch about 7 yearsExcept I need this event to happen for both the transparent element and also the elements below it.
-
iHowell almost 7 yearsEven though I found it about 3 hours into creating a work around, thanks for keeping me from completing it!
-
twobob almost 7 yearsIf one clicks an element - and starts a drag - and then passes the mouse over an element supposedly marked as
"pointer-events:none;"
sadly the supposedly inert element will still stop the event chain. -
Johann almost 7 yearsWould help if you had indicated where to put this. Does it belong on the content beneath the overlay or on the overlay?
-
JanD almost 7 years@AndroidDev: I clarified the answer – is it clear now where to apply the property?
-
Johann almost 7 yearsBut what if you just want to let some event like the scroll event to pass through but for the top element to still respond to all other events. Setting pointer-events to none kills all the events on the top element.
-
Dmitry about 6 yearsCan it be boiled down to just:
.parent * { pointer-events:all; }
for children? -
Design.Garden over 4 yearsIt should be "pointer-events: auto;". The "all" value applies only to SVGs. See developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
-
David about 2 years@Dmitry Can confirm, that did work:
.parent { pointer-events:none; }
and.parent * { pointer-events:auto; }