javascripthtmlcsscursor

How can I change the style of cursor only when another element is being hovered over?


I'm trying to code a custom cursor that changes its style when hovering over certain elements.

As shown in my code, I tried to define a function that changed the cursor's style when hovering over the div, calling on it using <div id="control" onmouseover="cursorFill()></div>". I expected the cursor to change on hover and change back once it was no longer over the div, but instead it changed and did not change back.

I would prefer to do this in vanilla JavaScript if possible (without jQuery or other extensions).

const cursor = document.querySelector('#cursor');
document.addEventListener('mousemove', (e) => {
  cursor.style.left = e.pageX + 'px';
  cursor.style.top = e.pageY + 'px';
})

function cursorFill() {
  document.getElementById("cursor").style.backgroundColor = "#fff";
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  cursor: none;
}

body {
  background-color: #000;
  align-items: center;
  justify-content: center;
  display: flex;
}

#cursor {
  position: fixed;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 5px solid #fff;
  background-color: transparent;
  transform: translate(-50%, -50%);
  pointer-events: none;
  mix-blend-mode: difference;
}

#control {
  background-color: #fff;
  width: 10em;
  height: 10em;
  margin-top: 50vh;
}
<div id="cursor"></div>
<div id="control" onmouseover="cursorFill()"></div>


Solution

  • The issue is because you only set the background colour when the mouse is over #control. It needs to be re-set back to its original value when the mouse leaves the element too.

    Note in the following example that I removed the inline onmouseover attribute, as using these is bad practice and should be avoided. Use unobrusive event handlers in your JS instead.

    Also note that I amended the logic to add/remove a CSS class from the element. This is to avoid having any CSS logic in your JS code.

    Lastly, I changed the event from mouseover, which fires once for every pixel the mouse hovers over the element, and as such is overkill for this use case, to mouseenter, which only fires once when the mouse first enters the boundary of the target element.

    With those changes made, your code would look something like this:

    const cursor = document.querySelector('#cursor');
    const control = document.querySelector('#control');
    
    document.addEventListener('mousemove', (e) => {
      cursor.style.left = e.pageX + 'px';
      cursor.style.top = e.pageY + 'px';
    })
    
    control.addEventListener('mouseenter', () => cursor.classList.add('over'));
    control.addEventListener('mouseleave', () => cursor.classList.remove('over'));
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      cursor: none;
    }
    
    body {
      background-color: #000;
      align-items: center;
      justify-content: center;
      display: flex;
    }
    
    #cursor {
      position: fixed;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      border: 5px solid #fff;
      background-color: transparent;
      transform: translate(-50%, -50%);
      pointer-events: none;
      mix-blend-mode: difference;
    }
    #cursor.over {
      background-color: #FFF;
    } 
    
    #control {
      background-color: #fff;
      width: 10em;
      height: 10em;
      margin-top: 50vh;
    }
    <div id="cursor"></div>
    <div id="control"></div>