How to ignore Hover/Mouseover events on specific element in CSS with the pointer-events property

Learn how to remove/ignore the mouseover/hover (:hover) event on specific HTML elements by using the pointer-events property.

I recently built a team gallery page for one of my clients. Each gallery item is represented by a UI card that uses an overlay that changes color when you move your mouse over it. But I ran into a problem, which inspired this tutorial.

UI Card content & structure

Each gallery card item consists of these elements:

  • Employee photo - black/white
  • Employee name - white
  • Employee role - white
  • A subtle dark background overlay

When users move their mouse over each card the background overlay transitions into a light semi-transparent yellow (brand color).

UI Card example

Since I want to keep this tutorial focused on solving a specific problem, here’s a simplified (design-wise) version of how the UI Card looked. Try moving your mouse over it and see the background color transition to a light yellow:

Employee Name
Employee Role

But there is a problem. You might already have spotted it. Try moving your mouse over the text area, do you see it the issue?

As soon as your mouse moves over the text element area, the hover event is canceled — and immediately turns from yellow, back to the default inactive state, with the gray color. Not acceptable!

Here’s the HTML code:

<div class="card">
  <div class="card-overlay"></div>
  <img
    class="card-image"
    src="https://lyngholm.dk/static/c2f22e08c2e0281f0c1d543498ccb58a/cad07/Lyngholm_Carsten_okt19_AS_web.jpg"
  />
  <div class="card-info">
    <div class="card-name">Employee Name</div>
    <div class="card-role">Employee Role</div>
  </div>
</div>

And the CSS:

.card {
  max-width: 350px;
  position: relative;
}

.card-overlay {
  background-image: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.5));
  height: 100%;
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  transition: background-color 0.6s;
}

.card-overlay:hover {
  background-color: rgba(255, 204, 7, 0.5);
}

.card-image {
  max-width: 100%;
  display: block;
}

.card-info {
  position: absolute;
  bottom: 2rem;
  left: 2rem;
}

.card-name,
.card-role {
  color: white;
  font-size: 1.5rem;
  line-height: 1.25;
  padding: 0.25rem;
}

.card-name {
  font-weight: bold;
}

So why does the hover event get canceled when you move your mouse over the text area?

Because of the stacking order of the HTML. The stacking order is usually controlled by the CSS z-index property. However, there is a default stacking order that occurs, if you don’t address it directly with CSS first.

z-index is a stack order CSS property. The element that has the highest z-index value (number) is put in front of other elements — assuming their position value is the same. The default z-index value of all elements on a web page is auto, which is the same as zero 0.

So since we have two elements that are both absolute positioned and they both have a default z-index of auto (0) which of them is in front of the other in the stacking order (one has to win)?

The one that comes last in your HTML wins.

In this case, the <div class="card-info"> container that contains the name and role text elements comes after the card-overlay element:

<div class="card">
  <div class="card-overlay"></div>
  <img
    class="card-image"
    src="https://lyngholm.dk/static/c2f22e08c2e0281f0c1d543498ccb58a/cad07/Lyngholm_Carsten_okt19_AS_web.jpg"
  />
  <div class="card-info">
    <div class="card-name">Employee Name</div>
    <div class="card-role">Employee Role</div>
  </div>
</div>

On the UI Card example, as soon as you move your mouse over the text elements, you’re no longer hovering the overlay element, but the <class="card-info"> element, which doesn’t have a :hover (pseudo class) attached. Only .card has that (see the CSS code).

What can you do?

If you physically move the <div class="card-overlay"></div> element down below the <div class="card-info>...</div> element like this:

<div class="card">
  <img
    class="card-image"
    src="https://lyngholm.dk/static/c2f22e08c2e0281f0c1d543498ccb58a/cad07/Lyngholm_Carsten_okt19_AS_web.jpg"
  />
  <div class="card-info">
    <div class="card-name">Employee Name</div>
    <div class="card-role">Employee Role</div>
  </div>
  <div class="card-overlay"></div>
</div>

Then the stacking order will swap, and this happens:

Employee Name
Employee Role

Great, now the overlay transition is no longer interrupted when you move your mouse over the text area (try it).

But wait... Now that the stacking order has been switched around, the text elements get grayed out by the overlay, which is now in front/on top of it.

We solved a problem while creating another.

Let’s not use that approach, and move the <div class="card-overlay"> element back to its original position.

What if we instead give the .card-overlay class a z-index value of 1?

Now card-overlay will be put in front of card-info (which still has z-index: 0) because it has a higher stack order (z-index: 1) and now the color change on hover event will again work uninterrupted — which is great, but...

Unfortunately, doing this will result in the the exact same thing as before when we physically moved the <div class="card-overlay"> element below the <div class="card-info"> element. This time we just changed the stacking order directly with CSS. The text elements are still grayed out by the overlay.

This is unacceptable!

Pointer events to the rescue!

I suddenly remembered that CSS has a property called pointer-events which allows you to decide whether or not an element should react to pointer events.

Pointer events are anything that has to do you your mouse, such as clicking, scrolling, or moving your mouse over (hover) an element.

So I simply added pointer-events: none; to my .card-info class, like his:

.card-info {
  position: absolute;
  bottom: 2rem;
  left: 2rem;
  pointer-events: none; /* the fix! */
}

And now you can hover over the entire UI Card, including the text, without canceling the hover event — and the text elements retain their 100% white color:

Employee Name
Employee Role
Great success!

Check out the code CodePen.


Has this been helpful to you?

You can support my work by sharing this article with others, or perhaps buy me a cup of coffee 😊

Kofi

Share & Discuss on