Overlapped elements with opacity and handling the 'hover' on those

旧城冷巷雨未停 提交于 2019-12-06 01:27:34

There's a CSS only solution, which makes it a bit more efficient. Like this for example:

body {
  background-image: linear-gradient(45deg, transparent 50%, #aaa 75%);
  background-size: 20px 20px;
}

#a {
  position: absolute;
  width: 150px;
  height: 150px;
  top: 50px;
  left: 50px;
  background: rgba(255, 0, 0, 1);
}

#b {
  position: absolute;
  width: 150px;
  height: 150px;
  top: 125px;
  left: 125px;
  background: rgba(255, 0, 0, 1);
}

#wrapper {
  opacity: 0.5;
}

/* instead of changing the classes,  
you can use selectors like this:*/

#wrapper:hover #a:hover,
#wrapper:hover #b:hover {
  opacity: 1;
  z-index: 10;
}

#wrapper:hover {
  opacity: 1;
}

#wrapper:hover #b,
#wrapper:hover #a {
  opacity: 0.5;
  z-index: -1;
}
<div id=wrapper>
  <div id="a">
  </div>
  <div id="b">
  </div>
</div>

I tried with elements at absolute positions. In this case I'm able to move each of them on top the wrapper on mouse enter, then back to their position on mouse leave, via pure JavaScript.

I have expanded the example to 3 elements, where your code shows the artifacts, and added borders to actually see the overlapping.

CODEPEN

The HTML:

<div id=top>
  <div id=wrapper>
    <div class="first" onMouseEnter="hover3b(event)" onMouseLeave="hover3e(event)"></div>
    <div class="second" onMouseEnter="hover3b(event)" onMouseLeave="hover3e(event)"></div>
    <div class="third" onMouseEnter="hover3b(event)" onMouseLeave="hover3e(event)"></div>
  </div>
</div>

The CSS:

body {
  background-image: linear-gradient(45deg, transparent 50%, #aaa 75%);
  background-size: 20px 20px;
}

.first, .second, .third {
  width: 100px;
  height: 100px;
  background-color: red;
  position: absolute;
  border: 3px solid black;
}

#wrapper {
  width: 200px;
  height: 200px;
  background-color: yellow;
  border: 3px solid green;
  opacity: 0.6;
}

.first { left: 0px; top: 0px; }
.second { left: 80px; top: 80px; }
.third { left: 160px; top: 160px; }

The JavaScript:

var from = null; // remember where to put back the element
function hover3b(e) {
  var t = e.target;
  from = t.nextElementSibling;
  if (!from)
    from = null;
  document.getElementById("top").appendChild(t);
}
function hover3e(e) {
  document.getElementById("wrapper").insertBefore(e.target, from);
}

Solution

As described in the requirement, the solution starts with creating two elements and probably a wrapper to those.

<div class="wrapper">
  <div class="first"></div>
  <div class="second"></div>
</div>

Now, we style them to match the design.

.first,
.second {
  width: 100px;
  height: 100px;
  background-color: red;
  opacity: 0.6;
}

And the below lines of code for the overlap.

.second {
  margin-left: 50px;
  margin-top: -50px;
}

The problem with this approach is that the opacity will not be consistent on the overlapped region and it gets a darker shade.

Note that this is not a bug with the browsers and the reason for this behaviour is explained here.


The right approach

The better way to handle this situation is to avoid making the children elements transparent and instead set 'opacity' in the parent level. And while hover, toggle these opacity levels between the parent and children with JS.

$(".first, .second").hover(function() {
  $(".wrapper, .first, .second").not(this).toggleClass("add-opacity");
});

Also, the hover on overlapped region would cause flickering due to change in stack order, which can be handled by setting z-index to the hovered element.

.first:hover,
.second:hover {
  z-index: 1;
}

CODEPEN

Hope this helps.

Here's another approach using Pointer_events

whenever you hover on an element you disable the pointer-events on the other :

$('.first').hover(
  () => { $('.second').css({'pointer-events': 'none'})},
  () => { $('.second').css({'pointer-events': 'auto'})
})

$('.second').hover(
  () => {$('.first').css({'pointer-events': 'none'})},
  () => {$('.first').css({'pointer-events': 'auto'})
})
* {
  box-sizing: border-box;
  padding: 0;
  margin: 0;
  border: 0;
}

body {
  background-image: linear-gradient(45deg, transparent 50%, #aaa 75%);
  background-size: 20px 20px;
}

.wrapper {
  margin-top: 10px;
  margin-left: 10px;
}

.first {
  width: 100px;
  height: 100px;
  background: rgba(255, 0, 0, 0.6);
}

.second {
  width: 99px;
  height: 98px;
  margin-top: -49px;
  margin-left: 50px;
  background: -webkit-linear-gradient(transparent 50%, rgb(255, 0, 0) 50%), -webkit-linear-gradient(0deg, transparent 50%, rgb(255, 0, 0) 50%);
  opacity: 0.6;
}

.first:hover,
.second:hover {
  background: rgba(255, 0, 0, 1);
  opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
  <div class="first" id="first"></div>
  <div class="second" id="second"></div>
</div>

check the compatibility for this as it will work in most browsers except Safari ( as of now ).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!