0

I have a webpage where two divs are on top of each other, and both are the same width, so the top div completely covers the bottom div. The challenge: I need users to be able to interact with the lower div. By interact, I mean click, hover (as determined using mouseenter and mouseleave in JS), highlight text, etc.

I'm already familiar with pointer-events (as discussed here), but setting it to none on the top div hasn't resolved the issue. Is there anything I can do to make the lower div interactive without placing it above the upper div (i.e. without changing its z-index)? Note that I haven't explicitly set the z-index on either div; it's set by their order in the document.


Update: Here's a CodePen demonstrating an example of this behavior. In the actual code I'm working with, .upper contains nested elements, and the button animation is run in JS (using GSAP) rather than as a CSS animation.

https://codepen.io/jmindel/pen/WNGJjLe

jmindel
  • 465
  • 1
  • 7
  • 16
  • It would be possible to add the event handlers to the parent element of both divs and then refer to the lower div within them. – sbgib Jan 05 '21 at 08:13
  • Thank you! Which event handlers would I be adding? There are some button elements, for example, which are nested within the lower div that are much smaller than both the lower and upper divs, so I'm unsure of how I'd access them through the upper div. For highlighting text, I never explicitly set up an event handler on the lower div; I'm not sure what I'd need to change. – jmindel Jan 05 '21 at 08:14
  • Can you explain "*hasn't resolved the issue*"? When you set pointer-events to none, that div will stop receiving mouse events. – Wais Kamal Jan 05 '21 at 08:16
  • I mean that setting `pointer-events` to `none` didn't allow me to hover over elements nested in the lower div and get the desired interaction, nor to highlight text nested in the lower div. It's possible that `pointer-events` is what's in fact making the entire area (which is the size of the entire viewport) non-interactive, but that didn't seem to be the case before I added it. – jmindel Jan 05 '21 at 08:17
  • It wouldn't make sense to put buttons and text that the user is supposed to directly interact with behind something, so why wouldn't you just change the z-index at this point? – sbgib Jan 05 '21 at 08:18
  • You should add pointer-events to the div you want to click through, not to the whole body. – Wais Kamal Jan 05 '21 at 08:19
  • @sbgib It's a limitation of some libraries I'm using, unfortunately. I'm using ScrollMagic for animations and to pin some elements, but it only allows pinning one element at a time (or so it seems; there isn't good documentation on pinning multiple elements at once). As a result, I've had to group both pinned elements, which are at opposite ends of the viewport, and place them both in one div ("top div") atop the main content. I'm also using Parallax.js, for which this would have had to be the case to display a parallax scene over part of the content anyway. – jmindel Jan 05 '21 at 08:19
  • @WaisKamal I haven't added it to the whole body (or at least, not the literal `body` element). I've added it to the top div, which effectively covers the entire viewport (and thus perhaps an equivalent and undesirable effect). – jmindel Jan 05 '21 at 08:21
  • Can you make a [JSFiddle](https://jsfiddle.net) or a [StackSnippet](https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/) of what you are encountering? When you set pointer-events to none on a div that covers the whole viewport area, then that div acts as if it is not there as far as mouse events are involved. – Wais Kamal Jan 05 '21 at 08:24
  • @WaisKamal Sure! I'm working in React, so I'll try to find a simpler example of the issue and post an edit shortly. – jmindel Jan 05 '21 at 08:26
  • @WaisKamal Added! My apologies for the delay. – jmindel Jan 05 '21 at 08:40
  • In your [example](https://codepen.io/jmindel/pen/WNGJjLe), setting `pointer-events: none` on css class `upper` successfully allowed me to interact with the button / select text as expected. Here's the working example: https://codepen.io/gonusi/pen/NWRMvmB – Kasparas Anusauskas Jan 05 '21 at 11:02
  • We at GreenSock don't recommend ScrollMagic. Instead we recommend the official scroll plugin: [ScrollTrigger](https://greensock.com/scrolltrigger/)! It's better in every way. – Zach Saucier Jan 06 '21 at 14:58
  • @ZachSaucier Thank you! And thank you for a fantastic product! GSAP has made my front-end experience so much more enjoyable. I was unaware of ScrollTrigger until a few days ago, but plan to migrate sometime soon. – jmindel Jan 06 '21 at 15:17

1 Answers1

0

Fixed--many thanks to those in the comments who helped! Using pointer-events: none was indeed the fix, but the question was on which elements. ScrollMagic wraps all pinned elements in another div whose class it allows you to change: when pinning, use .setPin(element, { spacerClass: <the name of a class with pointer-events disabled> }), as per this example on ScrollMagic's website. Then, for each element in the pinned container that should still be interactive, add pointer-events: all to its style. There's likely a semantically better way to pin multiple elements without interaction issues, but this was the simplest fix I could find.

jmindel
  • 465
  • 1
  • 7
  • 16
  • Beware the trap of frameworks, especially jQuery. You will negate your ability to code real JavaScript which is already a very high level language. Each version of jQuery negates the last and you'll forever be trapped in maintenance hell. Multiple versions, poor performance, etc. Do the research if you want to avoid being just another cog in a machine. Good luck. – John Jan 05 '21 at 19:19
  • 1
    I'm not actually using jQuery, thankfully (very much agreed on the concerns you've shared here), unless it's a dependency of one of the libraries I'm using (which I believe it is not). I'm running on a combination of React, Typescript, and Webpack. Many thanks nonetheless! – jmindel Jan 05 '21 at 19:21