Miki
Miki

Reputation: 1818

Pass scroll events through canvas to div below

I want the text to scroll vertically no matter if the pointer is on top of the grey area (the container div) or the red area (the canvas element on top). Currently the canvas prevents the scroll events to be propagated below. Is there a CSS only solution to this?

See the codepen and the image below.

enter image description here

This is my code:

<div class="container">
  <div class="content">
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
  </div>
  <canvas class="overlay">
  </canvas>
</div>

.container {
    background: #CCCCCC;
    width: 200px;
    height: 200px;
    position: relative;
    border: 4px black solid;
}
.content {
    width: 100%;
    height: 100%;
    overflow: scroll;
}
.overlay {
    border:1px solid black;
    background: rgba(255,0,0,0.5);
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left:0;
    height: 150px;
    width: 150px;
}

Upvotes: 2

Views: 3954

Answers (3)

Madacol
Madacol

Reputation: 4276

Still requires js

It's a simpler version of enxaneta answer, but requires knowing beforehand which node will be scrolled

overlay.addEventListener("wheel", (event)=>{
  scrollingNode.scroll({
    top: event.deltaY + scrollingNode.scrollTop,
    behavior: 'smooth'
  });
  event.preventDefault();
})
.container {
    background: #CCCCCC;
    width: 200px;
    height: 200px;
    position: relative;
    border: 4px black solid;
}
.content {
    width: 100%;
    height: 100%;
    overflow: scroll;
}
.overlay {
    border:1px solid black;
    background: rgba(255,0,0,0.5);
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left:0;
    height: 150px;
    width: 150px;
  pointer-events:auto;
}
<div class="container" id="container">
  <div class="content" id="scrollingNode">
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
  </div>
  <canvas class="overlay" id="overlay">
  </canvas>
</div>

Upvotes: 1

enxaneta
enxaneta

Reputation: 33044

Instead of solving the problem you may avoid it. In the following example I'm using pointer-events:none for the canvas only on wheel. This will allow you to scroll through the canvas. However as soon as you click the container I'm deleting the inline styles for the canvas. Alternatively I could have written test.style.pointerEvents = "initial"

test.addEventListener("wheel", ()=>{
  test.style.pointerEvents = "none";
  console.log("w")
})

container.addEventListener("click",(evt)=>{test.style.cssText = "";
                                      console.log(oMousePos(test, evt))})

function oMousePos(elmt, evt) {
      var ClientRect = elmt.getBoundingClientRect();
                return { //objeto
                x: Math.round(evt.clientX - ClientRect.left),
                y: Math.round(evt.clientY - ClientRect.top)
      }
}
.container {
    background: #CCCCCC;
    width: 200px;
    height: 200px;
    position: relative;
    border: 4px black solid;
}
.content {
    width: 100%;
    height: 100%;
    overflow: scroll;
}
.overlay {
    border:1px solid black;
    background: rgba(255,0,0,0.5);
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left:0;
    height: 150px;
    width: 150px;
  pointer-events:auto;
}
<div class="container" id="container">
  <div class="content">
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
  </div>
  <canvas class="overlay" id="test">
  </canvas>
</div>

Upvotes: 4

Quinton Chester
Quinton Chester

Reputation: 336

You were so close.

You need to set the position to fixed on the .container class and then you will need to add pointer-events: none; to your .overlay class. That does the trick.

See below:

.container {
    background: #CCCCCC;
    width: 200px;
    height: 200px;
    position: fixed;
    border: 4px black solid;
}
.content {
    width: 100%;
    height: 100%;
    overflow: scroll;
}
.overlay {
    border:1px solid black;
    background: rgba(255,0,0,0.5);
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left:0;
    height: 150px;
    width: 150px;
    pointer-events: none;
}
<div class="container">
  <div class="content">
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
    blah<br/>blah<br/>blah<br/>blah<br/>blah<br/>
  </div>
  <canvas class="overlay">
  </canvas>
</div>

Upvotes: 1

Related Questions