Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate custom cursor when hovering on a link

I have a custom image cursor for my body and links.

What I would like to achieve is hovering the link the cursor should transition into the link's cursor image, rather than it just changing straight away.

Currently, I have this code:

html {
  height:100%;
}
body {
  cursor:url(https://i.imgur.com/odlAwsz.png), auto  !important;
  width:100%;
  height:100%;
  background:red;
}

a {
  cursor:url(https://i.imgur.com/yxX4Snm.png), auto !important;
}
<a href="#">I'm a link</a>

As you can see above there is no transition between the two circle icons when hovering <a>.

I tried achieving this with CSS, but with no success. How can this be achieved using JavaScript?

like image 582
probablybest Avatar asked Jul 11 '18 09:07

probablybest


People also ask

How does your cursor change when you hover over a link?

By default, the mouse pointer is an arrow. When you hover over text you get the I-beam cursor, whereas the pointer changes to a hand cursor when the mouse is over a hyperlink.

How do I make a custom animated cursor?

To create an animated cursor use the "File/New/New Cursor..." menu item. This will open the New Cursor dialog. On the New Cursor dialog select the desired image size and bit count. Make sure that the "Animated Cursor (ANI)" radio button is selected.


1 Answers

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.

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

  2. the target is a <a> element, can be checked with jQuery's .is method:

      const isLinkTag = target.is('a');
    
  3. whether or not #cursor has the class .hoveredCursor i.e. #cursor is already hovering. With the method .hasClass:

       const isHovered = cursor.hasClass('hoveredCursor');
    
  4. 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;
    } 
  1. 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).

like image 127
Ivan Avatar answered Oct 06 '22 04:10

Ivan