Optimise Javascript cursor so it runs smoother (mainly Safari)

I concede :slight_smile:

It was worth exploring though. Thanks.

1 Like

Wow - thanks for all this. I really appreciate how much effort you’re going into here. Sorry for going dark, I’ve actually been away for a few days so picking this up again now :slight_smile:

The CodePen my version is based off worked pretty smooth - but in Safari it went crazy! Something to do with Safari not liking trying to animate transform I think but not sure. When we ‘resolved’ that, when you stopped moving the mouse the dot wasn’t always centred in the outer circle so more code was added. So we may’ve went a bit OTT!

@paulOB can’t believe (well I can) there was another post about that which may’ve helped with the issue. I did search but obviously missed it.

Testing this: https://codepen.io/paulobrien/embed/MWQZKxM? in Chrome/Firefox/Safari it works super smooth! I guess I need to take this and add to my project and see how it behaves with the additional content. And also the adding/removing classes depending what is interacted with.

1 Like

Hey all, sorry I’ve been away so picking this up again (sorry)!

I tried implementing some of the JS that performed really well into my own example but it instantly seems jumpy, even in Chrome, am I missing something. Updated example below (sure it’s me)…

One thing I am thinking is as I do this, I wonder if I’m going to lose the smooth transitions of the cursor to arrows on the carousel - but one step at a time eh?

Try using a setTimeout of 0. That way it will be done as quickly as the web browser is capable of handling things, but it won’t risk lagging other aspects of the browser to an appreciable degree.

1 Like

It actually works much better in Safari than your previous version and doesn’t stutter to a halt.

If you do what @Paul_Wilkins says above and set the timeout to zero you can create the circle delay effect in css.


In cursor.outer add a transform with delay.

  transition: border-color 0.12s ease-out, height 0.12s ease-out,
    top 0.12s ease-out, left 0.12s ease-out, opacity 0.12s ease-out,
    width 0.12s ease-out,transform .05s ease-out;

Then set timeout to zero as follows.

if (!timeout) {
      timeout = setTimeout(function () {
        timeout = null;
        cursor.style.transform = `translate3d(${x - 0}px, ${y - 0}px, 0)`;
      }, 0);

That seems smoother to me.

Note that in your demo you have cursorInner in camel case but you have used cursorinner a few times by mistake.:slight_smile:


As the cursor is being moved with transform you won’t be able to rotate it form left to tight when over the carousel because you are dynamically updating the transform property inline and you would also have to include the rotation as all other values are reset when you use transform.

I would suggest that you create the arrow effect without transform like this.

I haven’t added any transitions to it but you could play around with ti.

1 Like

Thanks for this!

Yeah I was going to say I went through and updated so it took into consideration the previous comments: https://codepen.io/moy/pen/oNEOePO

I think that transform is the tricky thing and something I’ll need to look into. The benefit of the translate was that when hovering over a link, the outer circle shrunk towards the middle. Without it shrinks to the top/right corner. So I’ll need to see if there’s a way I can work around that. Maybe adding pixel values to the hover state and see how that looks.

Think flipping the arrow might be trickier but I’ll see what I can do!

Do you think now this is smoother and the code more streamline, reintroducing the transform would maybe be ok? Or is this an issue with Safari and how it handles transform/transition elements?

Thanks again, really appreciate all of this! :slight_smile:

I’ve shown how to do it in my example and you just position half a rotated box at either side of the line as required. :slight_smile:

You can offset the circle like this:

  margin:-8px 0 0 -8px;

I’ve added that all to my demo:

It seems to work exactly the same in Safari now and is quite smooth.


I have tested your last version in various browsers on pc and in Firefox, Opera and Edge it is very smooth. However in chrome the dot jumps about flickering on and off.

Also finding that the cursor sometimes gets stuck in the top corner and I need to refresh the page.

I wonder if the fact it is playing within an iframe in codepen is also an issue?

Edit: Copied the code across to vscode. For me in Chrome the circle moves smoothly but does suffer the clipping issue I mentioned before and the dot movement is still erratic.

1 Like

Do you get the same problems with the basic version?

As a matter of interest I found another demo with a similar cursor effect and that too fails badly in my old Safari. The outer circle hardly moves at all.

1 Like

I did want to respond with [something] in the wind comes to mind, but that is not the attitude :biggrin:

I think one of the main issues might be the clipping effect. That may well explain the dot flickering on and off. As it is, my brain cannot decipher whether I am moving the circle or the dot.

My fix as you know was to add a good bit of padding to the elements, so that the clipping wasn’t noticeable. On a positive note, maybe that would help.

The basic one to my eye is smoother.

It’s smooth, but again has the same problem with clipping. Move the cursor at even a reasonable speed and the dot almost disappears. This issue does seem to be limited to chrome from what I can tell.


I’ll have a look tomorrow and play around again :slight_smile:

I think the middle dot needs to be bigger because transforms in Chrome do end up leaving or erasing artefacts of sorts in intensive situations.


Didn’t really come to any conclusions as on the mac I don’t get any clipping effect. I increased the size of the dot which I think makes sense and is easier to follow with the eye.

It still looks a lot smoother in Safari than the original (and that other demo I linked to). Chrome on the mac seems fine also but I think any further improvements would be more js related than css.

I think the main problem is that following the cursor is quite an intensive task and to make it look smooth is quite tricky especially when there are other things going on.

I did play around with slightly different css methods but didn’t really see any major differences.


Yeah that is a lot smoother than the original example I based my code off but there seems to be a really jump/stutter when hovering over a link.

I think the cursor in the CodePen’s after are much, much smoother. They work great and I can’t thank everyone enough …I can’t keep up with your replies which is amazing how much you’re looking into this.

I think I liked the using the divs to transform into and flip to arrow from a smooth animation/visual point of view but maybe I need to make that compromise for performance.

I haven’t had a chance to explore this option you found a post for yet: https://stackoverflow.com/questions/66033305/move-object-with-easing-not-working-properly-in-safari

But imagine it’s pretty close to what we have with the transform. I might need to rework the markup but I wonder if something simple on my last example where I have a container div with the 2 cursor effects in could work. Then I could target a different element. Thinking out-loud, hmmm I’m not sure that’ll do it as that’d also need height/width and position values …but I’ll give it a shot!

…or maybe in the JS I can add something to the transform/rotate when the relevant class is added.

1 Like

Why not just replace the cursor with a svg image?
No need to hide the cursor.
There are a few google hits on “js svg custom cursor”.
eg. https://codyhouse.co/nuggets/custom-cursor

1 Like

That could probably help with the arrow images when over the slideshow :).

However the main issue was the outer ring effect which can’t be done in a single image because of the lazy follow behind effect.

A css only cursor image would have been my preferred approach and not worry about the lazy effect :slight_smile:

1 Like

Yeah an SVG would make it easier :sweat_smile:

But unfortunately the goal for this is the smooth animation and transition/morphing of the cursor :disappointed:

I’m away for a few days but I’m hopefully going to pick this up again next week and try and nail it once and for all. I’m wondering, as I add a class to the cursor for it to rotate. Maybe I just update the translate/rotate in the JS for that - but I’ll let you’s know how I get on!

I saw this demo on codepen which also works quite well in my old Safari and doesn’t seem to lag.

It uses the canvas element and draws the morphing effect so only the one canvas element gets moved as such. Obviously it’s a lot more complex as the element has to be drawn depending on which way the cursor was moving. It’s too complex for me to try and code but someone watching may be able to redraw the circle and dot effect instead of the gooey effect :slight_smile:

A post was split to a new topic: Site dropped from Google index