Jack Averill
Jack Averill

Reputation: 841

Why doesn't my div follow my cursor consistently across all browsers?

I have a circle div that follows my cursor and changes size/ color when I hover a link. I'm happy with the way my code works in Chrome, Brave and Opera browsers - it's smooth, and it remains fixed when the mouse is scrolled. In Safari and Firefox however, it's not working so well.

In safari, it's very jerky and the div lags behind the cursor, and in Firefox there is a glitch when the cursor hovers the link. (If the cursor is moved over the link quickly, the circle seems to move away very suddenly and catches up with the cursor).

Can anyone see any obvious errors in my code? I'm very new to jQuery and this is something I've pieced together from tutorials, trial & error and the help of kind people on stackoverflow.

Thanking you in advance for any help.

Update: It seems to be the transition property transition: transform 0.1s; I added to .circle-cursor that is causing the glitchy behaviour in Safari and Firefox.

JSFiddle - https://jsfiddle.net/ecapvukw/1/

jQuery(document).ready(function($) {

  var $circle = $('.circle-cursor');
  var half_cWidth = $circle.width() / 2;
  var half_cHeight = $circle.height() / 2;

  $(document).mousemove(function(e) {
    $circle.css({
      transform: 'translate(' + (e.clientX - half_cHeight) + 'px, ' + (e.clientY - half_cWidth) + 'px)'
    });
  });

  $("a").hover(
    function() {
      $("body").addClass("cursor-hover");
    },
    function() {
      $("body").removeClass("cursor-hover");
    }
  );

});
body {
  position: relative;
  height: 1000px;
  width: 100%;
  margin: 0;
}

a {
  float: left;
  padding: 20px;
  background: #efefef;
}

.circle-cursor {
  position: fixed;
  z-index: 99999;
  -webkit-transition: -webkit-transform 0.1s;
  -o-transition: transform 0.1s;
  transition: transform 0.1s;
}

.circle-inner {
  position: absolute;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  pointer-events: none;
  background-color: rgba(0, 0, 0, 0.05);
  -webkit-transform: translate(-50%, -50%);
  -ms-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
  -webkit-transition: width .2s, height .2s, opacity 1s, background-color .2s, -webkit-transform .2s;
  -o-transition: transform .2s, width .2s, height .2s, opacity 1s, background-color .2s;
  transition: transform .2s, width .2s, height .2s, opacity 1s, background-color .2s;
}

body.cursor-hover .circle-inner {
  width: 70px;
  height: 70px;
  background-color: rgba(237, 85, 0, 0.5);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span class="circle-cursor">
    <span class="circle-inner"></span>
</span>
<a href="">This is a link.</a>

Upvotes: 1

Views: 178

Answers (1)

biberman
biberman

Reputation: 5767

I think there are some issues:

  • in firefox the event looks different, clientX and clientY can only be found in 'originalEvent', so addressing them directly is faster then letting the script search the whole event for eventually nested properties
  • for transform the script has more to calculate then for simple 'top' and 'left' (when no transition is needed)
  • the circle width and height is 0 – when you take it from 'circle-inner' you got it and then you don't need the translate(-50%, -50%) (and the second transform)

So this is faster:

const half_cWidth = $('.circle-inner').width() / 2;
const half_cHeight = $('.circle-inner').height() / 2;
...
circle.css({
    'top': (e.originalEvent.clientY - half_cHeight) + 'px', 
    'left': (e.originalEvent.clientX - half_cWidth) + 'px'
});

Working example:

$(document).ready(function($) {

  var circle = $('.circle-cursor');
  const half_cWidth = $('.circle-inner').width() / 2;
  const half_cHeight = $('.circle-inner').height() / 2;

  $(document).mousemove(function(e) {
    circle.css({
      'top': (e.originalEvent.clientY - half_cHeight) + 'px',
      'left': (e.originalEvent.clientX - half_cWidth) + 'px'
    });
  });

  $("a").hover(
    function() {
      $(".circle-inner").addClass("cursor-hover");
    },
    function() {
      $(".circle-inner").removeClass("cursor-hover");
    }
  );

});
body {
  position: relative;
  height: 1000px;
  width: 100%;
  margin: 0;
}

a {
  float: left;
  padding: 20px;
  background: #efefef;
}

.circle-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 99999;
  -webkit-transition: top .1s, left .1s;
  -o-transition: top .1s, left .1s;
  transition: top .1s, left .1s;
}

.circle-inner {
  position: absolute;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  pointer-events: none;
  background-color: rgba(0, 0, 0, 0.05);
  -webkit-transition: width .2s, height .2s, opacity 1s, background-color .2s;
  -o-transition: width .2s, height .2s, opacity 1s, background-color .2s;
  transition: width .2s, height .2s, opacity 1s, background-color .2s;
}

.circle-inner.cursor-hover {
  width: 70px;
  height: 70px;
  background-color: rgba(237, 85, 0, 0.5);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<span class="circle-cursor">
    <span class="circle-inner"></span>
</span>
<a href="">This is a link.</a>

If don't want to use top and left here is an working example with transform:

jQuery(document).ready(function($) {

  const circle = $('.circle-cursor');
  const half_cWidth = $('.circle-inner').width() / 2;
  const half_cHeight = $('.circle-inner').height() / 2;

  $(document).mousemove(function(e) {
    circle.css({
      transform: 'translate(' + (e.originalEvent.clientX - half_cHeight) + 'px, ' + (e.originalEvent.clientY - half_cWidth) + 'px)'
    });
  });

  $("a").hover(
    function() {
      $("body").addClass("cursor-hover");
    },
    function() {
      $("body").removeClass("cursor-hover");
    }
  );

});
body {
  position: relative;
  height: 1000px;
  width: 100%;
  margin: 0;
}

a {
  float: left;
  padding: 20px;
  background: #efefef;
}

.circle-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 99999;
  -webkit-transition: -webkit-transform 0.1s;
  -o-transition: transform 0.1s;
  transition: transform 0.1s;
}

.circle-inner {
  position: absolute;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  pointer-events: none;
  background-color: rgba(0, 0, 0, 0.05);
  -webkit-transition: width .2s, height .2s, opacity 1s, background-color .2s;
  -o-transition: width .2s, height .2s, opacity 1s, background-color .2s;
  transition: width .2s, height .2s, opacity 1s, background-color .2s;
}

body.cursor-hover .circle-inner {
  width: 70px;
  height: 70px;
  background-color: rgba(237, 85, 0, 0.5);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<span class="circle-cursor">
    <span class="circle-inner"></span>
</span>
<a href="">This is a link.</a>

Upvotes: 1

Related Questions