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:
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>
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>