Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send click to background div

I have two divs: One is the background that contains clickable items, and the second is an overlay div that is scrollable. I would like to be able to click the items in the first div without turning off the scrolling capability of the second div.

Here is an example fiddle: https://jsfiddle.net/samlalani/yu832xad/36/

Is this possible? I would appreciate any suggestions and would prefer not to use jQuery (edit: Using vanilla JavaScript is fine, just not jQuery). Thank you.

Here is the HTML:

<div id="wrapper">
  <table>
    <tr><td onclick="alert('1')" class="red">111111</td></tr>
    <tr><td>2</td></tr>
    <tr><td onclick="alert('3')" class="red">333333</td></tr>
    <tr><td>4</td></tr>
    <tr><td>5</td></tr>
    <tr><td onclick="alert('6')" class="red">666666</td></tr>
    <tr><td>7</td></tr>
    <tr><td>8</td></tr>
    <tr><td>9</td></tr>
    <tr><td>10</td></tr>
  </table>
  <p>
  The ones, threes and sixes should be clickable, and the magenta div should be scrollable.
  </p>
</div>
<div id="overlay" onclick="overlayClick()">
  <div>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut venenatis tempus est, sit amet faucibus neque congue eu. Aliquam porta enim tortor, condimentum auctor urna vehicula eu. Suspendisse blandit sapien sapien, eu volutpat odio venenatis eleifend. Donec imperdiet maximus posuere. Mauris rutrum venenatis massa et sodales. Nullam convallis sodales tellus. Ut sodales sem nec lacus viverra, nec vehicula enim dictum. Nam sed molestie massa. Vestibulum eget dui felis. Mauris consequat mauris nec nibh aliquam dapibus. Phasellus id laoreet est. Donec sit amet egestas ex, id malesuada dui. Donec imperdiet, sapien ac dignissim dignissim, lectus dolor convallis sapien, vel elementum arcu leo vel diam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
  </div>
</div>

Here is the CSS:

#wrapper {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 1;
  width: 200px;
  height: 50px;
}
#overlay {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 2;
  opacity: 0.5;
  background-color: magenta;
  width: 200px;
  height: 100px;
  overflow: scroll;
}
.red {
  background-color: red;
  color: yellow;
}

Here is the JavaScript:

function overlayClick() {
  alert('overlayClick');
}
like image 721
user1828108 Avatar asked Nov 17 '19 21:11

user1828108


2 Answers

Consider using elementsFromPoint property of document. (For IE/Edge support use msElementsFromPoint).

I've just added a couple of lines to your JS, see the basic snippet below:

function overlayClick(e) {
  alert('overlayClick');
  document.elementsFromPoint(e.pageX, e.pageY)
  .find(el => el.classList.contains('red') && el.click())
}
#wrapper {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 1;
  width: 200px;
  height: 50px;
}

#overlay {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 2;
  opacity: 0.5;
  background-color: magenta;
  width: 200px;
  height: 100px;
  overflow: scroll;
}

.red {
  background-color: red;
  color: yellow;
}
<div id="wrapper">
  <table>
    <tr><td onclick="alert('1')" class="red">111111</td></tr>
    <tr><td>2</td></tr>
    <tr><td onclick="alert('3')" class="red">333333</td></tr>
    <tr><td>4</td></tr>
    <tr><td>5</td></tr>
    <tr><td onclick="alert('6')" class="red">666666</td></tr>
    <tr><td>7</td></tr>
    <tr><td>8</td></tr>
    <tr><td>9</td></tr>
    <tr><td>10</td></tr>
  </table>
  <p>
  The ones, threes and sixes should be clickable, and the magenta div should be scrollable.
  </p>
</div>
<div id="overlay" onclick="overlayClick(event)">
  <div>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut venenatis tempus est, sit amet faucibus neque congue eu. Aliquam porta enim tortor, condimentum auctor urna vehicula eu. Suspendisse blandit sapien sapien, eu volutpat odio venenatis eleifend. Donec imperdiet maximus posuere. Mauris rutrum venenatis massa et sodales. Nullam convallis sodales tellus. Ut sodales sem nec lacus viverra, nec vehicula enim dictum. Nam sed molestie massa. Vestibulum eget dui felis. Mauris consequat mauris nec nibh aliquam dapibus. Phasellus id laoreet est. Donec sit amet egestas ex, id malesuada dui. Donec imperdiet, sapien ac dignissim dignissim, lectus dolor convallis sapien, vel elementum arcu leo vel diam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
  </div>
</div>
like image 53
Kosh Avatar answered Sep 20 '22 20:09

Kosh


Edit (js solution with code) - for pure css alternative, see below

I think Kosh Very's solution is much better. It is much cleaner. I did not know about the elementsFromPoint property.

Yes, I think we can do pretty much everything you asked for with jquery. I will leave the previous info below just in case someone in the future might find the pure css method useful.

I know you asked for vanilla js and not jquery, but as per comments below I am providing a jquery solution. The same may be possible with vanilla js but it is beyond my skill level, at least the jquery may provide a starting point and may serve others with similar questions in future.

  1. Put a generic table with the same size elements as the target table over the overlay, this will function as a click-grid. Set it to pointer-events:none;

  2. Give the click-grid cells numbered data attributes so we can generically target 1st, 2nd, 3rd, etc. rows of the target table. Set the click-grid cells background-color:transparent;

  3. Listen for mousedown on the overlay to enable the pointer-events on the click-grid.

  4. Listen for mouseup on the click-grid cells and use their data attributes to target the correct row of the target-table and trigger a click.

  5. After triggering the click re-disable click-grid pointer events.

  6. On the overlay mousedown function we should also re-disable click-grid pointer events after a short delay in case the user clicks the overlay but not actually on a click-grid cell. So this is a delayed backup to make sure the click-grid pointer-events don't accidentally get left active.

https://jsfiddle.net/rehtnvf8/10/

The only drawback here seems to be that you can't do hover effects on the underlying targets. You weren't doing so before and it was not in your requirements, so I think this should be suitable. I believe it is possible to do the hover effects and probably do this more elegantly using jquery's .mousemove but getting that to work was a little over my head. Also, in the examples the extra elements are written into the html, while it would probably be better, to add them to the page with javascript.

Here is the code sample for reference as well

$(document).ready(function(){
	//.click-grid .cg-src function fired on mouseup
  $.overlayClick = function(event) {
  	//prevent default probably not needed
    event.preventDefault();
    //the table where we find targets
    var tabl = $('.cg-target');
    //the firing element
    var clickSrc = $(event.target);
    //get data attr of firing element
    var clickTrgt = $(clickSrc).data('cgt');
    //use data attr to count down table elements
    //and locate target row
    var tablTrgt = tabl.find('tr').eq(clickTrgt);
    //find td within target row and trigger click
    tablTrgt.find('td').trigger('click');
    //disable pointer events on .click-grid
    $('.click-grid').css('pointer-events', 'none');
  }
  //#overlay function fired on mousedown
  $.overlayDown = function() {
  	//mousedown on #overlay enable .click-grid pointer-events
    $('.click-grid').css('pointer-events', 'all');
    //in case click was not over .cg-src
    //disable .click-grid pointer events after short delay
    setTimeout(function () {
      $('.click-grid').css('pointer-events', 'none');
    }, 300);
  }
  //listen for clicks, mousedown on #overlay, mouseup on cg-src
  $(document).on('mousedown', '#overlay', $.overlayDown);
  $('.click-grid').on('mouseup', '.cg-src', $.overlayClick);

});
body {
  position: relative;
}
#wrapper {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 0;
  width: 200px;
  height: 50px;
}
#overlay {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 5;
  opacity: 0.5;
  background-color: magenta;
  width: 200px;
  height: 100px;
  overflow: scroll;
}
.scroll-content {
  position: relative;
  z-index: -1;
  cursor: pointer;
}
td {
  height: 1.2em;
}
.click-grid {
  position: absolute;
  top: 10;
  left: 10;
  z-index: 10;
  pointer-events: none;
}
.click-grid td {
  width: 4em;
  height: 1.2em;
  background-color: transparent;
}

.red {
  background-color: red;
  color: yellow;
}
.red:hover {
  background-color: blue;
  color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="wrapper">
  <table class="cg-target">
    <tr><td onclick="alert('1')" class="red red-1">111111</td></tr>
    <tr><td class="no-pointer">2</td></tr>
    <tr><td onclick="alert('3')" class="red">333333</td></tr>
    <tr><td>4</td></tr>
    <tr><td>5</td></tr>
    <tr><td onclick="alert('6')" class="red">666666</td></tr>
    <tr><td>7</td></tr>
    <tr><td>8</td></tr>
    <tr><td>9</td></tr>
    <tr><td>10</td></tr>
  </table>
  <p>
  The ones, threes and sixes should be clickable, and the magenta div should be scrollable.
  </p>
</div>
<div id=overlay>
  <div class="scroll-content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut venenatis tempus est, sit amet faucibus neque congue eu. Aliquam porta enim tortor, condimentum auctor urna vehicula eu. Suspendisse blandit sapien sapien, eu volutpat odio venenatis eleifend. Donec imperdiet maximus posuere. Mauris rutrum venenatis massa et sodales. Nullam convallis sodales tellus. Ut sodales sem nec lacus viverra, nec vehicula enim dictum. Nam sed molestie massa. Vestibulum eget dui felis. Mauris consequat mauris nec nibh aliquam dapibus. Phasellus id laoreet est. Donec sit amet egestas ex, id malesuada dui. Donec imperdiet, sapien ac dignissim dignissim, lectus dolor convallis sapien, vel elementum arcu leo vel diam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
  </div>
</div>
<table class="click-grid">
  <tr><td class="cg-src" data-cgt="0"></td></tr>
  <tr><td class="cg-src" data-cgt="1"></td></tr>
  <tr><td class="cg-src" data-cgt="2"></td></tr>
  <tr><td class="cg-src" data-cgt="3"></td></tr>
</table>

Original Answer (pure css)

Okay, so what you are trying to do, is not really possible with pure html/css. Maybe you could do with javascript.

That said, using pure css, we can get fairly close to what you are after by putting some of the table elements inside the overlay. We can use position: fixed; so they are taken out of the layout flow, and z-index to put them behind the text. Then we use pointer-events: none; on the div containing the text.

Note that the pointer-events property in css has pretty good support at this point yet is still technically considered 'experimental,' so caution should be exercised before using it in production.

https://jsfiddle.net/ako05wpr/3/

<div id="wrapper">
  <table>
    <tr><td onclick="alert('1')" class="red">111111</td></tr>
    <tr><td class="no-pointer">2</td></tr>
    <tr><td onclick="alert('3')" class="red">333333</td></tr>
    <tr><td>4</td></tr>
    <tr><td>5</td></tr>
    <tr><td onclick="alert('6')" class="red">666666</td></tr>
    <tr><td>7</td></tr>
    <tr><td>8</td></tr>
    <tr><td>9</td></tr>
    <tr><td>10</td></tr>
  </table>
  <p>
  The ones, threes and sixes should be clickable, and the magenta div should be scrollable.
  </p>
</div>
<div id="overlay" onclick="overlayClick()">
  <table class="behind">
    <tr><td onclick="alert('1')" class="red">111111</td></tr>
    <tr><td>2</td></tr>
    <tr><td onclick="alert('3')" class="red">333333</td></tr>
  </table>
  <div class="scroll-content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut venenatis tempus est, sit amet faucibus neque congue eu. Aliquam porta enim tortor, condimentum auctor urna vehicula eu. Suspendisse blandit sapien sapien, eu volutpat odio venenatis eleifend. Donec imperdiet maximus posuere. Mauris rutrum venenatis massa et sodales. Nullam convallis sodales tellus. Ut sodales sem nec lacus viverra, nec vehicula enim dictum. Nam sed molestie massa. Vestibulum eget dui felis. Mauris consequat mauris nec nibh aliquam dapibus. Phasellus id laoreet est. Donec sit amet egestas ex, id malesuada dui. Donec imperdiet, sapien ac dignissim dignissim, lectus dolor convallis sapien, vel elementum arcu leo vel diam. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.  </div>
</div>
#wrapper {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 1;
  width: 200px;
  height: 50px;
}
#overlay {
  position: absolute;
  left: 10;
  top: 10;
  z-index: 2;
  opacity: 0.5;
  background-color: magenta;
  width: 200px;
  height: 100px;
  overflow: scroll;
}
.scroll-content {
  position: relative;
  z-index: 1;
  pointer-events: none;
}
.behind {
  position: fixed;
  z-index: -1;
}
.behind, .behind tr, .behind td {
  pointer-events: none;
}
.behind tr td.red {
  pointer-events: all;
}
.red {
  background-color: red;
  color: yellow;
}
.red:hover {
  background-color: blue;
  color: yellow;
}

I used smaller table which only duplicates those first three rows, and covers those same three rows of the original table. Alternatively you could remove those rows from the original table and position under the overlay.

I think this is quite close to your goal. The issue remains though, that when hovering the .red clickable table elements behind the text, the text is not scrollable simultaneously. I minimized this by setting pointer-events: none; on all the table elements except .red so it is only the actual button itself which inhibits scrolling. This is not possible to overcome with just css. as the mouse can not interact with two elements simultaneously.

You can effect a child or direct sibling of an element you interact with, but that is indirectly. You aren't actually interacting with multiple elements. Only interacting with the one element, which is indirectly effecting style changes on children or direct siblings, and you can't do scrolling like that.

like image 33
Veneseme Tyras Avatar answered Sep 21 '22 20:09

Veneseme Tyras