Pass mouse events through absolutely-positioned element

136,182

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:

  1. removing the top layer on mousedown,
  2. passing the x and y coordinates from the event to the document.elementFromPoint method to get the element underneath, and then
  3. 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.

Share:
136,182
s4y
Author by

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, 2022

Comments

  • s4y
    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
    s4y almost 15 years
    Thanks 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
    s4y almost 13 years
    Thanks! 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
    Nathan about 12 years
  • Dan Abramov
    Dan Abramov about 12 years
    Woah, this just saved me hours.
  • s4y
    s4y over 11 years
    I 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
    jpeltoniemi about 11 years
    Awesome, 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
    Mohammed A. Al Jama about 10 years
    Thanks, I never knew this actually exists. it saved me hours
  • Eric Rowell
    Eric Rowell about 10 years
    Awesome! A note on browser support... curse you IE! foiled again. One day IE, one day.
  • Impossibear
    Impossibear over 9 years
    The 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
    netpoetica over 9 years
    Is there an equivalent for Touch events? touch-events: none; or the like?
  • Juan Cortés
    Juan Cortés almost 9 years
    Awesome, right after the high of discovering pointer-events:none and the imminent let-down of having children nodes affected, you save the day :)
  • Allisone
    Allisone almost 9 years
    ;) very glad about that
  • Shelvacu
    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
    swelet over 7 years
    Never have gone to consult Google about anything to find an answer as simple as this. Simply awesome.
  • RaisinBranCrunch
    RaisinBranCrunch about 7 years
    Except I need this event to happen for both the transparent element and also the elements below it.
  • iHowell
    iHowell almost 7 years
    Even though I found it about 3 hours into creating a work around, thanks for keeping me from completing it!
  • twobob
    twobob almost 7 years
    If 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
    Johann almost 7 years
    Would help if you had indicated where to put this. Does it belong on the content beneath the overlay or on the overlay?
  • JanD
    JanD almost 7 years
    @AndroidDev: I clarified the answer – is it clear now where to apply the property?
  • Johann
    Johann almost 7 years
    But 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
    Dmitry about 6 years
    Can it be boiled down to just: .parent * { pointer-events:all; } for children?
  • Design.Garden
    Design.Garden over 4 years
    It should be "pointer-events: auto;". The "all" value applies only to SVGs. See developer.mozilla.org/en-US/docs/Web/CSS/pointer-events
  • David
    David about 2 years
    @Dmitry Can confirm, that did work: .parent { pointer-events:none; } and .parent * { pointer-events:auto; }