DEV Community

Batuhan
Batuhan

Posted on

Custom Cursor with CSS and jQuery [Detailed]

Hey everyone! 2 days ago i posted I Built My Personal Website and one of the questions was What library did you use for the mouse pointer effect?. The answer is i used no library. I did it all by myself and today i am going to show you how i did it.

First things first, we have to create our custom cursor style.

Cursor Style

 .cursor{
   position: fixed;
   width: 20px;
   height: 20px;
   border-radius: 50%;
   background-color: #f5f5f5;
   pointer-events: none;
   mix-blend-mode: difference;
   z-index: 999;

   transition: transform 0.2s;
 }
Enter fullscreen mode Exit fullscreen mode

Why do we use?

position: fixed;
Enter fullscreen mode Exit fullscreen mode

It is because when we start to scroll we don't want our custom cursor to stay where we start to scroll. If you use position: absolute instead of fixed, cursor won't be moving as you scroll down or up the page. To prevent that you have to give the fixed value to position.

Why do we use?

pointer-events: none;
Enter fullscreen mode Exit fullscreen mode

Your cursor is right on top of the custom cursor you created. And whenever you want to click a link or see a hover statement this custom cursor will prevent that to be happen. If you give the none value to pointer-events you will be able to click anything you want.

What is...

mix-blend-mode: difference;
Enter fullscreen mode Exit fullscreen mode

The mix-blend-mode property defines how an element’s content should blend with its background.

difference: this subtracts the darker of the two colors from the lightest color.

And so this allows you to see the content behind your cursor easily.


jQuery DOM Manipulation

It is time to use some jQuery to make our

<div class="cursor"></div>
Enter fullscreen mode Exit fullscreen mode

element follow the default cursor.

$(document).ready(function(){
 var cursor = $('.cursor');
});
Enter fullscreen mode Exit fullscreen mode

Instead of writing $('.cursor') everytime and to make our job easier we stored it in a variable named cursor. Now let's make it follow as we move the mouse.

$(document).ready(function(){
 var cursor = $('.cursor');

 $(window).mousemove(function(e) {
        cursor.css({
            top: e.clientY - cursor.height() / 2,
            left: e.clientX - cursor.width() / 2
        });
    });
});
Enter fullscreen mode Exit fullscreen mode

We selected our window object and when we move our mouse in it we want our cursor's top and left positions to change. To make it happen we manipulate its css from here.

What is...

top: e.clientY
left: e.clientX
Enter fullscreen mode Exit fullscreen mode

clientY and clientX are relative to the upper left edge of the content area (the viewport) of the browser window. This point does not move even if the user moves a scrollbar from within the browser.

pageY and pageX are relative to the top left of the fully rendered content area in the browser. This reference point is below the URL bar and back button in the upper left.

And by using clientY instead of pageY we maintain our custom cursor to stay at the same position.

As you can see, to keep our custom cursor in the right position we have to give both

position: fixed;
Enter fullscreen mode Exit fullscreen mode

(in css)
and

top: e.clientY
left: e.clientX
Enter fullscreen mode Exit fullscreen mode

(in jQuery)
properties.

Why do we add...

top: e.clientY - cursor.height() / 2
left: e.clientX - cursor.width() / 2
Enter fullscreen mode Exit fullscreen mode

Because we want the cursor we created to be perfectly centered to our default one. As you can see above we gave height: 20px and width: 20px to our cursor.
To get the right point and center it we give

- cursor.height() / 2
- cursor.width() / 2
Enter fullscreen mode Exit fullscreen mode

If you didn't get it, to center absolute positioned elements we give

top: 50%;
left: 50%;
transform: translate(-50%, -50%);
Enter fullscreen mode Exit fullscreen mode

This transform: translate(-50%, -50%) perfectly centers the element by taking off half of its height and width. This example is similar to what we did on jQuery. -cursor.height()/2 and -cursor.width()/2 are doing the same thing.

What is going to happen when we leave our mouse from browser screen?

$(window)
        .mouseleave(function() {
            cursor.css({
                opacity: "0"
            });
        })
        .mouseenter(function() {
            cursor.css({
                opacity: "1"
            });
        });
Enter fullscreen mode Exit fullscreen mode

We don't want our custom cursor to be visible at the position where we left the screen.

With this code

$(window).mouseleave(function(){
cursor.css({opacity: "0"});
});
Enter fullscreen mode Exit fullscreen mode

whenever we leave the screen our custom cursor's opacity will be 0 and can't be seen.

And with this one

$(window).mouseenter(function(){
cursor.css({opacity: "1"});
});
Enter fullscreen mode Exit fullscreen mode

whenever our mouse is on the screen the custom cursor's opacity will be 1 and can be seen.

How do you understand if you click or not?

$(window)
        .mousedown(function() {
            cursor.css({
                transform: "scale(.2)"
            });
        })
        .mouseup(function() {
            cursor.css({
                transform: "scale(1)"
            });
        });
Enter fullscreen mode Exit fullscreen mode

With these lines of code when we click (which is mousedown) our cursor scales down to 0.2 and when we don't (which is mouseup) it comes to its normal statement and scales back to 1.

Managing the hover statements

$(".link")
        .mouseenter(function() {
            cursor.css({
                transform: "scale(3.2)"
            });
        })
        .mouseleave(function() {
            cursor.css({
                transform: "scale(1)"
            });
        });
Enter fullscreen mode Exit fullscreen mode

As you can see we have a class named link. If you have elements which have some effects on hover or you want your clickable items to be seen by user and want your custom cursor to change whenever you hover these elements, you can give every element that have this effect a class named link and so you can manipulate it from jQuery.

If your mouse is on the element(which is mouseenter) which has a link class, your cursor scales up to 3.2 and if you leave the hover state (which is mouseleave) it scales back to its normal state which is 1. You can give any class name you want and manipulate your custom cursor as you wish. This is just an example, you don't have to do the same.

Final

Don't forget these lines

html,
*{
cursor: none;
}
Enter fullscreen mode Exit fullscreen mode

to make the default cursor unseen.

At last we have our custom cursor created and functioning as we desire.

Don't forget to place your cursor element right on top of the closing body tag.

<body>

<!--Some other elements  -->

<div class="cursor"></div>
</body>
Enter fullscreen mode Exit fullscreen mode

Whole jQuery Code

$(document).ready(function(){
var cursor = $(".cursor");

    $(window).mousemove(function(e) {
        cursor.css({
            top: e.clientY - cursor.height() / 2,
            left: e.clientX - cursor.width() / 2
        });
    });

    $(window)
        .mouseleave(function() {
            cursor.css({
                opacity: "0"
            });
        })
        .mouseenter(function() {
            cursor.css({
                opacity: "1"
            });
        });

    $(".link")
        .mouseenter(function() {
            cursor.css({
                transform: "scale(3.2)"
            });
        })
        .mouseleave(function() {
            cursor.css({
                transform: "scale(1)"
            });
        });

    $(window)
        .mousedown(function() {
            cursor.css({
                transform: "scale(.2)"
            });
        })
        .mouseup(function() {
            cursor.css({
                transform: "scale(1)"
            });
        });
});
Enter fullscreen mode Exit fullscreen mode

An example for you to see how it works

(To get the true experience please go to codepen)

Also you can use TweenMax for custom cursor animations. I didn't use it before but you can give it a shot if you want.

Thanks for your time. Have a good day <3

Top comments (14)

Collapse
 
leob profile image
leob

Man that's some clever stuff, the pointer/cursor effect is one of the most original and creative things I've seen for a long time. Amazing what you can do nowadays with just standard CSS and some Javascript. Didn't you consider "going all the way" and using vanilla Javascript instead of jQuery? Probably wouldn't even be that hard to do.

Collapse
 
b4two profile image
Batuhan

thanks sir, i will try it with vanilla js next time

Collapse
 
leob profile image
leob

Not saying that you have to, but I think it wouldn't be that hard, and it means you're doing all of this wizardry with only the things that are built in to the browser, no frameworks, no libraries ... how cool it that? And you're already 90% there.

Collapse
 
anteamens profile image
Anthony Eamens

I signed up just to thank you for this, I have been looking to implement something similar and it's perfect! Thanks

Collapse
 
fren profile image
⚓ Carlos Faria

mix-blend-mode not working for you on Chrome? Try adding this to your css

html{
  // Fix mix-blend-mode for cursor on chrome
  background: #fff;
}
Collapse
 
crycx profile image
crycx

Nice one. Like the colors and style!

Collapse
 
thejudejoshua profile image
Jude Joshua

Thank you so much for sharing this. Been struggling with a cursor effect for hours now but this was a great help!

Collapse
 
jeffreywky profile image
K.Y.

How do i add a second cursor that follows the main dot?

Collapse
 
njanadesign profile image
Noureddine JANA

how can I do this in WordPress, I can't add an the div with its class in the body?

Collapse
 
jeanlou86 profile image
jeanlou86

The cursor is blurry when hovering/scaling up on Safari.
Any fix for that?

Thanks!

Collapse
 
xcrap profile image
César Couto

Any idea why the cursor doesn't move while scrolling?

Collapse
 
lagalga profile image
Heriberto Noguera • Edited

Thank you ;)
I've got a problem that some elements are not triggering… they're on a modal content div… maybe is that the reason mouseenter() is not working?

Collapse
 
lagalga profile image
Heriberto Noguera

I think i got it… maybe the JS is not loading one the new loaded modal content… so i've added a new code to that modal page with its specific target and now it works ;)