cursor Hover issues when used along with cursor moving function

63 views Asked by At

I am trying to create a custom mouse cursor where the body tag gets some classes applied depending upon the status of mouse cursor. Like:

  1. cursor-moving: whenever the mouse is moved
  2. cursor-idle: whenever the mouse is idle
  3. cursor-hover: whenever the mouse is moved over an anchor or a button tag.

But this javascript code is not working when I try to hover over the link elements. I tried to do a console, and it shows cursor-hover is working, but very intermittently and that too for a tiny second.

Hint: I have also written a style which will change the background-color of body when this hover thing works.

const customCursor = document.querySelector(".cursor");
let isCursorMoving = false;
let cursorIdleTimeout;
let isCursorOverLink = false;

function updateCursor(event) {
  const x = event.clientX + "px";
  const y = event.clientY + "px";

  customCursor.style.setProperty("--cursor-left", x);
  customCursor.style.setProperty("--cursor-top", y);

  if (!isCursorMoving) {
    document.body.classList.add("cursor-moving");
    document.body.classList.remove("cursor-idle");
    clearTimeout(cursorIdleTimeout);
  }

  cursorIdleTimeout = setTimeout(() => {
    isCursorMoving = false;
    document.body.classList.remove("cursor-moving");
    document.body.classList.add("cursor-idle");
  }, 1000);
}

function handleLinkEnter(event) {
  if (event.target.tagName === "A" || event.target.tagName === "BUTTON") {
    document.body.classList.add("cursor-hover");
  }
}

function handleLinkLeave(event) {
  if (event.target.tagName === "A" || event.target.tagName === "BUTTON") {
    document.body.classList.remove("cursor-hover");
  }
}

document.addEventListener("mousemove", updateCursor);
document.addEventListener("mouseenter", handleLinkEnter);
document.addEventListener("mouseleave", handleLinkLeave);
* {
  box-sizing: border-box;
}

body {
  background: #3f3f3f;
}

:root {
  --cursor-size: 32px;
  --tail-size: 1px;
  --tail-gap: 48px;
  --tail-color: #111;
  --cursor-color: #fff;
}

.cursor {
  position: fixed;
  left: var(--cursor-left, 0);
  top: var(--cursor-top, 0);
  width: var(--cursor-width, var(--cursor-size));
  height: var(--cursor-height, var(--cursor-size));
  z-index: 999999;
}

.cursor::before,
.cursor::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  background: var(--cursor-color);
  transform: translate(-50%, -50%);
}

.cursor::before {
  width: 1px;
  height: var(--cursor-size);
}

.cursor::after {
  width: var(--cursor-size);
  height: 1px;
}

.cursor .tail {
  position: absolute;
  left: 0;
  top: 0;
  background: var(--tail-color);
  opacity: 0.6;
}

.cursor .tail::before {
  content: "";
  position: absolute;
  background: var(--tail-color);
}

.cursor .tail-x {
  width: 100vw;
  height: var(--tail-size);
  left: var(--tail-gap);
}

.cursor .tail-x::before {
  left: calc(-100vw - var(--tail-gap) - var(--tail-gap));
  right: 0;
  width: 100vw;
  height: var(--tail-size);
}

.cursor .tail-y {
  width: var(--tail-size);
  height: 100vh;
  top: var(--tail-gap);
}

.cursor .tail-y::before {
  top: calc(-100vw - var(--tail-gap) - var(--tail-gap));
  bottom: 0;
  height: 100vw;
  width: var(--tail-size);
}

body {
  display: grid;
  height: 100vh;
  width: 100vw;
  place-items: center;
}

body.cursor-hover {
  background: yellow;
}

body.cursor-hover a {
  color: #000;
}

a {
  display: inline-block;
  color: #fff;
  padding: 4px;
}
<div class="cursor">
  <span class="tail tail-x"></span>
  <span class="tail tail-y"></span>
</div>

<a href="#">Link</a>

1

There are 1 answers

0
imhvost On BEST ANSWER

First, you obscure the link with the .cursor, because the .cursor has a larger z-index. Therefore, the .cursor should be given pointer-events:none;.

Second, you call the mouseenter and mouseleave events on the document and they do not affect the link in any way.

Fixed your code a bit:

const customCursor = document.querySelector('.cursor');
let isCursorMoving = false;
let cursorIdleTimeout;
let isCursorOverLink = false;

function updateCursor(event) {
  const {clientX, clientY} = event;
  customCursor.style.transform = `translate3d(${clientX}px, ${clientY}px, 0)`;
  
  const isHoverElement = event.target.tagName === 'A' || event.target.tagName === 'BUTTON'
  document.body.classList.toggle('cursor-hover', isHoverElement);

  if (!isCursorMoving) {
    document.body.classList.add('cursor-moving');
    document.body.classList.remove('cursor-idle');
    clearTimeout(cursorIdleTimeout);
  }

  cursorIdleTimeout = setTimeout(() => {
    isCursorMoving = false;
    document.body.classList.remove('cursor-moving');
    document.body.classList.add('cursor-idle');
  }, 1000);
}

window.addEventListener('mousemove', updateCursor);
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  cursor: none;
}

:root {
  --cursor-size: 32px;
  --tail-size: 1px;
  --tail-gap: 48px;
  --tail-color: #111;
  --cursor-color: #fff;
}

body {
  background: #3f3f3f;
  display: grid;
  height: 100dvh;
  place-items: center;
  overflow:hidden;
  transition: background-color .4s;
}

body.cursor-hover {
  background: yellow;
}

body.cursor-hover .cursor {
  color:blue;
}

body.cursor-hover a {
  color: #000;
}

a {
  color: #fff;
  padding: 4px;
}

.cursor {
  pointer-events: none;
  position: fixed;
  width: var(--cursor-size);
  height: var(--cursor-size);
  margin: calc(var(--cursor-size) / -2) 0 0 calc(var(--cursor-size) / -2);
  left: 0;
  top: 0;
  color: var(--cursor-color);
  transition: color .4s;
  z-index: 666;
}

.cursor:before,
.cursor:after {
  content: '';
  position: absolute;
  inset: calc(50% - var(--tail-size) / 2) 0 auto 0;
  background: currentColor;
  height: var(--tail-size);
}

.cursor::after {
  transform: rotate(90deg);
}

.cursor .tail {
  position: absolute;
  inset: 0;
  opacity: 0.6;
}

.cursor .tail:before,
.cursor .tail:after {
  content: '';
  position: absolute;
  background: var(--tail-color);
}

.cursor .tail-x:before,
.cursor .tail-x:after {
  top:calc(50% - var(--tail-size) / 2);
  height: var(--tail-size);
  width:100vmax;
}

.cursor .tail-x:before {
  right: calc(100% + var(--tail-gap))
}

.cursor .tail-x:after {
  left: calc(100% + var(--tail-gap))
}

.cursor .tail-y:before,
.cursor .tail-y:after {
  left: calc(50% - var(--tail-size) / 2);
  width: var(--tail-size);
  height: 100vmax;
}

.cursor .tail-y:before {
  bottom: calc(100% + var(--tail-gap))
}

.cursor .tail-y:after {
  top:calc(100% + var(--tail-gap))
}
<div class="cursor">
  <span class="tail tail-x"></span>
  <span class="tail tail-y"></span>
</div>
<a href="#">Link</a>