Click through a 'hole' cut with mix-blend-mode

1k views Asked by At

This looks like it should be possible, but the solution has eluded me for too long. Can you make a link clickable in a background revealed through a hole cut in a scrollable div using mix-blend-mode? I've tried the usual trick of pointer-events:none, but this doesn't work because the 'hole' is not really transparent, and probably also because the background is actually two levels down.

Here's my code so far:

<div style="height:400px;width:300px;margin:0 auto;background-image: repeating-linear-gradient(45deg, white 0px,#ebebeb 60px);border:1px solid grey;overflow:scroll;position:relative;">
  <div style="padding:20px"><span>
        lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor 
      </span>
    <br>
    <br>
    <a href="http://www.stackoverflow.com">Stack Overflow</a>
  </div>
  <div style="height:100%;width:100%;background:white;mix-blend-mode:hard-light;position:absolute;top:0;left:0;overflow:scroll">
    <div style="height:300px"></div>
    <div style="width: 90%;height: 50px;margin: 0 auto 0;border: solid 1px red;border-radius: 10px;background:grey;pointer-events:none;"></div>
    <div style="height:2000px"></div>
  </div>
</div>

If you scroll the content, you will see the background content come in to view - with a link - but I can't work out how to make the link clickable (if it's possible).

Thanks for any suggestions. A JS/Jquery solution would be fine, though straight CSS is the first preference.

3

There are 3 answers

0
Legends On

This should work:

$('#overlay').click(function(e) { 
  if(isElement($("a"),e)){
     console.log("link clicked");
  } 
});

function isElement($el, e){
  var xmin = $el.offset().left;
  var ymin = $el.offset().top;
  var xmax = xmin +  $el.width();
  var ymax = ymin + $el.height();
  
  if(e.pageX >= xmin && e.pageX <= xmax &&  e.pageY >= ymin && ymax >= e.pageY){
   return true;
  }
  return false;
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<div id="back" style="height:400px;width:300px;margin:0 auto;background:lightblue;background-image: repeating-linear-gradient(45deg, white 0px,#ebebeb 60px);border:1px solid grey;overflow:scroll;position:relative;">
  <div style="padding:20px"><span>
        lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor 
      </span>
    <br>
    <br>
    <a id="link" style="background-color:yellow;" href="http://www.stackoverflow.com">Stack Overflow</a>
  </div>
  <div style="height:100%;width:100%;background:white;mix-blend-mode:hard-light;position:absolute;top:0;left:0;overflow:scroll;">
    <div style="height:300px"></div>
    <div id="overlay" style="width: 90%;height: 50px;margin: 0 auto 0;border: solid 1px red;border-radius: 10px;background:grey"></div>
    <div style="height:2000px"></div>
  </div>
</div>
</body>
</html>

0
sideroxylon On

I'm going to post this here as a solution to my own needs (and very much in line with the solution proposed simultaneously by @sinisake above) - but I'd still be interested in a more generic solution.

(The click function is commented out because the sandbox won't allow window.open.)

$('#overlay').click(function() {
  alert('visible')
  if ($(this).offset().top < 230 && $(this).offset().top > 180) {
    //window.open($('#link').attr('href'), '_blank');
    alert($('#link').attr('href'), '_blank');
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="back" style="height:400px;width:300px;margin:0 auto;background:lightblue;background-image: repeating-linear-gradient(45deg, white 0px,#ebebeb 60px);border:1px solid grey;overflow:scroll;position:relative;">
  <div style="padding:20px"><span>
        lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor 
      </span>
    <br>
    <br>
    <a id="link" href="http://www.stackoverflow.com">Stack Overflow</a>
  </div>
  <div style="height:100%;width:100%;background:white;mix-blend-mode:hard-light;position:absolute;top:0;left:0;overflow:scroll;">
    <div style="height:300px"></div>
    <div id="overlay" style="width: 90%;height: 50px;margin: 0 auto 0;border: solid 1px red;border-radius: 10px;background:grey"></div>
    <div style="height:2000px"></div>
  </div>
</div>

1
Alvaro On

The mix-blend-mode CSS property describes how an element's content should blend with the content of the element's direct parent and the element's background.

Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode

Blending modes simply provide visual ways to mix layer colors, but the DOM is still the same. So in the way you are approaching it right now there is no possibility of clicking through that visual "hole".

You would need to use JavaScript to actually trigger a click in a link behind an element.

Using CSS, I found there is an option to click through. You can make use of pointer-events: none; this could make the link behind clickable. However, it would make the element not respond to any mouse event including scroll.

#a{pointer-events: none;}
<div style="height:400px;width:300px;margin:0 auto;background-image: repeating-linear-gradient(45deg, white 0px,#ebebeb 60px);border:1px solid grey;overflow:scroll;position:relative;">
  <div style="padding:20px"><span>
        lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor lorem ipsum amet sit dolor 
      </span>
    <br>
    <br>
    <a href="http://www.stackoverflow.com>Stack Overflow">Stack Overflow</a>
  </div>
  <div id="a" style="height:100%;width:100%;background:white;mix-blend-mode:hard-light;position:absolute;top:0;left:0;overflow:scroll">
    <div style="height:300px"></div>
    <div style="width: 90%;height: 50px;margin: 0 auto 0;border: solid 1px red;border-radius: 10px;background:grey;pointer-events:none;"></div>
    <div style="height:2000px"></div>
  </div>
</div>