Drarig29
Drarig29

Reputation: 2245

Prevent mouse events to go through child elements

In the example below, mouse events are going through the child (list items) when the mouse is between the item label and the horizontal colored bar.

This results in the item de-emphasizing although the mouse in still in its bounds. This is because of the margin I think... how could I prevent this?

const parent = document.querySelectorAll(".parent")[0];
const items = document.querySelectorAll(".parent li");

items.forEach((item) =>
    item.addEventListener("mouseenter", () => setHint(item))
);

parent.addEventListener("mouseout", () => setHint(false));

function setHint(item) {
    if (item) {
        items.forEach((i) => {
            i.classList.add(i === item ? "hovered" : "not-hovered");
        });
    } else {
        items.forEach((i) => {
            i.className = "";
        });
    }
}
.parent {
  margin: 20px;
  padding: 20px;
  list-style: none;
  background: lightblue;
  margin-block-start: 0;
  margin-block-end: 0;
  margin-inline-start: 0;
  margin-inline-end: 0;
}

.parent li {
  width: 100%;
  margin-bottom: 16px;
  line-height: 1.4;
  transition: opacity 0.2s ease;
  cursor: pointer;
}

.parent li.hovered {
  opacity: 1;
}

.parent li.not-hovered {
  opacity: 0.1 !important;
}

.parent li > span {
  display: flex;
  justify-content: space-between;
}

.child-label {
  font-size: 14px;
  margin-bottom: 4px;
}

.child-bar {
  position: relative;
  display: block;
  width: 100%;
  height: 8px;
  background: rgb(186, 186, 186);
}

.child-bar-fill {
  display: block;
  width: 0;
  height: 100%;
  transition: width 0.4s ease;
  background: #fe512c;
}
<ul class='parent'>
    <li>
        <span class='child-label'>
            <b>Lorem ipsum</b>
            <span>8 045</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 36.6749%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Dolor sit amet</b>
            <span>8 701</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 39.6654%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Consectetur adipiscing</b>
            <span>144</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.656455%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Sed do eiusmod</b>
            <span>806</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 3.67433%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Incididunt ut labore</b>
            <span>149</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.679249%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Dolore magna aliqua</b>
            <span>470</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 2.1426%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Enim ad minim veniam</b>
            <span>73</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.332786%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Cupidatat non proident</b>
            <span>87</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.396608%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Reprehenderit in voluptate</b>
            <span>3 461</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 15.7777%;'></span>
        </span>
    </li>
</ul>

Upvotes: 0

Views: 1123

Answers (2)

sigmus
sigmus

Reputation: 3237

I believe you can solve your problem with a CSS only approach like the one below, combining parent:hover and parent li:hover.

.parent {
  margin: 20px;
  padding: 20px;
  list-style: none;
  background: lightblue;
  margin-block-start: 0;
  margin-block-end: 0;
  margin-inline-start: 0;
  margin-inline-end: 0;
}

.parent li {
  width: 100%;
  margin-bottom: 16px;
  line-height: 1.4;
  transition: opacity 0.2s ease;
  cursor: pointer;
  opacity: 1;
}

.parent:hover li {
    opacity: 0.1;
}

.parent:hover li:hover {
    opacity: 1;
}

.parent li > span {
  display: flex;
  justify-content: space-between;
}

.child-label {
  font-size: 14px;
  margin-bottom: 4px;
}

.child-bar {
  position: relative;
  display: block;
  width: 100%;
  height: 8px;
  background: rgb(186, 186, 186);
}

.child-bar-fill {
  display: block;
  width: 0;
  height: 100%;
  transition: width 0.4s ease;
  background: #fe512c;
}
<ul class='parent'>
    <li>
        <span class='child-label'>
            <b>Lorem ipsum</b>
            <span>8 045</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 36.6749%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Dolor sit amet</b>
            <span>8 701</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 39.6654%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Consectetur adipiscing</b>
            <span>144</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.656455%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Sed do eiusmod</b>
            <span>806</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 3.67433%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Incididunt ut labore</b>
            <span>149</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.679249%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Dolore magna aliqua</b>
            <span>470</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 2.1426%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Enim ad minim veniam</b>
            <span>73</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.332786%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Cupidatat non proident</b>
            <span>87</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.396608%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Reprehenderit in voluptate</b>
            <span>3 461</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 15.7777%;'></span>
        </span>
    </li>
</ul>

Upvotes: 2

GrahamTheDev
GrahamTheDev

Reputation: 24815

If you want to use your current setup and JS all you need is pointer-events: none adding to your label and bars.

Because you are essentially targeting mouseover (via mouseenter and mouseout) for the <li>, when your mouse is over the label or bar it is no longer the item that is receiving mouseover and so triggers mouseout.

By adding pointer-events:none we are telling the browser to ignore all events on this item and let them pass through to the item below.

const parent = document.querySelectorAll(".parent")[0];
const items = document.querySelectorAll(".parent li");

items.forEach((item) =>
    item.addEventListener("mouseenter", () => setHint(item))
);

parent.addEventListener("mouseout", () => setHint(false));

function setHint(item) {
    if (item) {
        items.forEach((i) => {
            i.classList.add(i === item ? "hovered" : "not-hovered");
        });
    } else {
        items.forEach((i) => {
            i.className = "";
        });
    }
}
.parent {
  margin: 20px;
  padding: 20px;
  list-style: none;
  background: lightblue;
  margin-block-start: 0;
  margin-block-end: 0;
  margin-inline-start: 0;
  margin-inline-end: 0;
}

.parent li {
  width: 100%;
  margin-bottom: 16px;
  line-height: 1.4;
  transition: opacity 0.2s ease;
  cursor: pointer;
  display: block;
}

.parent li.hovered {
  opacity: 1;
}

.parent li.not-hovered {
  opacity: 0.1 !important;
}

.parent li > span {
  display: flex;
  justify-content: space-between;
}

.child-label {
  font-size: 14px;
  margin-bottom: 4px;
  pointer-events: none;
}

.child-bar {
  position: relative;
  display: block;
  width: 100%;
  height: 8px;
  background: rgb(186, 186, 186);
  pointer-events: none;
}

.child-bar-fill {
  display: block;
  width: 0;
  height: 100%;
  transition: width 0.4s ease;
  background: #fe512c;
  pointer-events: none;
}
<ul class='parent'>
    <li>
        <span class='child-label'>
            <b>Lorem ipsum</b>
            <span>8 045</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 36.6749%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Dolor sit amet</b>
            <span>8 701</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 39.6654%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Consectetur adipiscing</b>
            <span>144</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.656455%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Sed do eiusmod</b>
            <span>806</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 3.67433%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Incididunt ut labore</b>
            <span>149</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.679249%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Dolore magna aliqua</b>
            <span>470</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 2.1426%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Enim ad minim veniam</b>
            <span>73</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.332786%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Cupidatat non proident</b>
            <span>87</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 0.396608%;'></span>
        </span>
    </li>
    <li>
        <span class='child-label'>
            <b>Reprehenderit in voluptate</b>
            <span>3 461</span>
        </span>
        <span class='child-bar'>
            <span class='child-bar-fill' style='width: 15.7777%;'></span>
        </span>
    </li>
</ul>

Upvotes: 2

Related Questions