pointer-events

The article was first published on a personal blog

scenario

In a company project, I came across a scenario like this: When an item (with its icon, price, etc.) is hovering over the icon, a dangling toolTips should display its details. When the item is disabled, a black mask will be placed over the item, which is also not selected. Then the problem comes. But there is a black mask on it, what to do?

The code looks like this (some tags have been removed to prevent the code from being too long):

<style>
  .container {
    width: 500px;
    height: 300px;
    background: red;
    position: relative;
  }
  .mask {
    width: 100%;
    height: 100%;
    background: green;
    position: absolute;
    z-index: 2;
  }
  .content {
    width: 500px;
    height: 300px;
    background: blue;
  }
</style>
<body>
  <div class="container">
    <div class="mask"></div>
    <p class="content">I am content</p>
  </div>

  <script>
    const mask = document.querySelector('.mask');
    const container = document.querySelector('.container');
    const content = document.querySelector('.content');

    content.addEventListener('mouseenter'.() = > {
      console.log('content mouseenter');
    });
    mask.addEventListener('mouseenter'.() = > {
      console.log('mask mouseenter');
    });
    container.addEventListener('mouseenter'.() = > {
      console.log('container mouseenter');
    });
  </script>
</body>
Copy the code

However, it now works like this when I hover:

// container mouseenter
// mask mouseenter
Copy the code

At that time, I was thinking about how to solve this problem. There was a mask on it, but I couldn’t figure it out because mouseEnter should be triggered on content. So I asked my tutor, and she told me to try pointer-Events. Then came the words: wonderful.

What is pointer-events?

Let’s look at its definition on Mdn

The pointer-Events CSS property specifies under what circumstances, if any, a particular graphic element can be the trigger of mouse events.

It has a number of values:

/* Global values */
pointer-events: inherit;
pointer-events: initial;
pointer-events: unset;

/* Keyword values */
pointer-events: auto;
pointer-events: none;
/* The following attributes apply only to SVG */
pointer-events: visiblePainted;
pointer-events: visibleFill;
pointer-events: visibleStroke;
pointer-events: visible;
pointer-events: painted;
pointer-events: fill;
pointer-events: stroke;
pointer-events: all;
Copy the code

add pointer-events: None

// container mouseenter
// content mouseenter
Copy the code

Why is that? Mdn: Pointer-events: None

The element will never be a trigger for mouse events. However, mouse events can point to descendant elements when the pointer-events attribute of their descendant elements specifies other values, in which case the mouse event will fire the parent element’s event listener during the capture or bubble phase.

So if we add this property to the.mask, it won’t be the trigger of the mouse event, and then the trigger of the mouse event will be the.content, and that will solve the problem.

But we see this definition, however, when the descendant element also specifies this attribute and is not None, the mouse event can point to the descendant element, and the rest is omitted… Let’s try another demo:

<style>
  .mask-child {
    width: 200px;
    height: 300px;
    background: yellow;
    pointer-events: auto;
  }
</style>
<body>
  <div class="container">
    <div class="mask">
      <div class="mask-child"></div>
    </div>
    <p class="content">I am content</p>
  </div>

  <script>
    const maskChild = document.querySelector('.mask-child');

    maskChild.addEventListener('mouseenter'.() = > {
      console.log('maskChild mouseenter');
    });
  </script>
</body>
Copy the code

Add this to the code, and let’s look at it again. Notice that we added a.mask-child to the.mask, and then we also listened for its mouseEnter event. Let’s look at the effect again:

// container mouseenter
// mask mouseenter
// maskChild mouseenter
Copy the code

If you want to skip an element, you can set pointer-events: None on it, but note that the mouseEnter event for the mask is still triggered. Descendants should not specify pointer-events, otherwise it will still be invalid.

The sample

  1. Mouse events (drag, hover, click, etc.) are not triggered.
<style>
  button {
    pointer-events: none;
  }
</style>
<button onclick="handleClick()">test</button>
<script>
  function handleClick() {
    console.log('handleClick');
  }
</script>
Copy the code

HandleClick is not printed.

  1. And if it’s set:hover,:activePseudo classes are also not triggered.

If we wanted to cancel the hover effect on a disabled element, we might write something like this:

<p class="content disable"></p>

<style>
  .content:not(disable):hover{}</style>
Copy the code

Now we can just write it this way, isn’t it easier?

<p class="content disable"></p>

<style>
  .content.disable {
    pointer-events: none;
  }
  .content:hover{}</style>
Copy the code

An even easier way to do this is to put.disable below because of CSS precedence.

<p class="content disable"></p>

<style>
  .content:hover {
    background: black;
  }
  .content.disable {
    background: yellow;
  }
</style>
Copy the code

conclusion

The above is the whole content of the article, is to make a small record for yourself, I hope to help you.