javascripthtmlcssmousemove

Strange inconsistency bug when setting top and left style properties via js


I create a div element with fixed position and size. Then I set it's top and left style properties via js in the mousemove event handler.

const mouse = document.getElementById('mouse');
window.addEventListener("mousemove", e => {
  mouse.style.left = e.offsetX + 'px';
  mouse.style.top = e.offsetY + 'px';
  console.log(e.offsetX, e.offsetY);
});

https://jsfiddle.net/xqa91b23/4/ (wiggle your mouse around to see the bug)

It appears that about half of the assignments work, the rest of the time the css properties end up being set to 0px. I am logging the mouse position as passed into the mousemove event handler, and it does not correspond to the values which end up being assigned to the element's style attribute. The strangest part of this is that if I add transform: translate(-50px, -50px) to the element then the incorrect assignments incorporate this offset, ending up as 50px. This occurs in both chrome and firefox.

Some of the things I have tried:

This one has me banging my head against the wall. I have dynamically set offset properties in the past with no problem. My suspicion is that it has something to do with the number to string conversion applied by + 'px', but that doesn't explain the strange behavior when adding a translation.


Solution

  • The issue is because of the use of offsetX and offsetY properties of the event. These parameters are relative to event target, not the window i.e. when mousemove event triggers offsetX and offsetY are calculated based on #mouse. To fix this you need to use e.clientX and e.clientY.

    const mouse = document.getElementById('mouse');
    window.addEventListener("mousemove", e => {
      mouse.style.left = e.clientX + 'px';
      mouse.style.top = e.clientY + 'px';
      console.log(e.clientX, e.clientY);
    });
    #mouse {
      position: fixed;
      width: 100px;
      height: 100px;
      outline: 1px solid red;
    }
    <div id="mouse"></div>