Here's a way you can achieve: the following solution allows you to have custom HTML cursors that can transition from one state to another when hovering specific tags.
- Let's first create our custom HTML cursor:
#cursor {
width: 20px;
height: 20px;
position: absolute;
top: 0;
left: 0;
background: blue;
border-radius: 10px;
}
<div id="cursor"></div>
- Then we need to make this element track the position of the actual cursor:
$(document).mousemove(function(e) {
const cursor = $('#cursor');
const target = $(event.target);
// update position of cursor
cursor.css('left', e.clientX-10).css('top', e.clientY-10);
});
* {
cursor: none;
}
#cursor {
width: 20px;
height: 20px;
position: absolute;
top: 0;
left: 0;
background: blue;
border-radius: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cursor"></div>
When #cursor
will be hovering <a>
we will add a class (.hoveredCursor
) that will change #cursor
's initial properties (e.g. width
and height
). In order to not unnecessarily add or remove a class to the cursor on mousemove
we can check for two things:
the target is a <a>
element, can be checked with jQuery's .is
method:
const isLinkTag = target.is('a');
whether or not #cursor
has the class .hoveredCursor
i.e. #cursor
is already hovering. With the method .hasClass
:
const isHovered = cursor.hasClass('hoveredCursor');
You can set any property to .hoveredCursor
, when hovering these will be added to #cursor
's initial property (you might need to use !important
to overwrite styles), for example:
.hoveredCursor {
width: 10px !important;
height: 10px !important;
}
Then set the transition
property of #cursor
to make it smooth:
#cursor {
transition: linear height 0.2s, linear width 0.2s;
}
- one issue you might come across is having
#cursor
get in the way of the event.target
meaning target will be #cursor
. This results in some bad behavior (#cursor
will be switching back and forth between the two states...)
Setting none
to #cursor
's pointer-events
will solve that (the event will simply ignore #cursor
).
Here is the final code:
$(document).mousemove(function(e) {
const cursor = $('#cursor');
const target = $(event.target);
// update position of cursor
cursor.css('left', e.clientX-10).css('top', e.clientY-10);
const isLinkTag = target.is('a');
const isHovered = cursor.hasClass('hoveredCursor');
// toggle the cursor class if necessary
if(isLinkTag && !isHovered) {
cursor.addClass('hoveredCursor');
} else if(!isLinkTag && isHovered) {
cursor.removeClass('hoveredCursor');
}
});
$(document).mouseleave(function(e) {
const cursor = $('#cursor');
cursor.hide()
});
$(document).mouseenter(function(e) {
const cursor = $('#cursor');
cursor.show()
});
* {
cursor: none;
}
#cursor {
pointer-events: none;
width: 20px;
height: 20px;
position: absolute;
top: 0;
left: 0;
display: none;
background: blue;
border-radius: 10px;
transition: linear height 0.2s, linear width 0.2s;
}
.hoveredCursor {
width: 10px !important;
height: 10px !important;
}
a {
font-size: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="cursor"></div>
<a href="#">This is a link</a>
Note: I have added a mouseenter
and mouseleave
to the document too so that the custom cursor hides or shows accordingly.
The advantage of using such method is it allows you to transition between two sets of properties for any given elements (by tags - here <a>
- or even by selector).