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).