Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use absolute coordinates with transform translate

I can make a box that follows the mouse with the following.

document.addEventListener('mousemove', (e) => {
    document.documentElement.style.setProperty('--mouse-x', e.clientX + 'px');
    document.documentElement.style.setProperty('--mouse-y', e.clientY + 'px');
});
.box {
  width: 50px;
  height: 50px;
  
  background-color: blue;
  
  transform: translate(calc(var(--mouse-x) - 50%), calc(var(--mouse-y) - 50%));
}
<div class="box"></div>

but as soon as the element is not positioned at the top left, it breaks.

document.addEventListener('mousemove', (e) => {
    document.documentElement.style.setProperty('--mouse-x', e.clientX + 'px');
    document.documentElement.style.setProperty('--mouse-y', e.clientY + 'px');
});
.box {
  width: 50px;
  height: 50px;
  
  margin-left: 150px;
  
  background-color: blue;
  
  transform: translate(calc(var(--mouse-x) - 50%), calc(var(--mouse-y) - 50%));
}
<div class="box"></div>

How can I use absolute coordinates with a transform? I don't want to use left/top/position: fixed/absolute because I need to preserve the position of the element in the flow.

I could use JavaScript to grab the central position and then use that infomation to get the correct center.

document.addEventListener('mousemove', (e) => {
    document.documentElement.style.setProperty('--mouse-x', e.clientX + 'px');
    document.documentElement.style.setProperty('--mouse-y', e.clientY + 'px');
});

window.addEventListener('load', (e) => {
    const box = document.querySelector('.box');
    const rect = box.getBoundingClientRect();
    box.setAttribute('style', `
      --center-x: ${rect.left + (rect.width / 2)}px;
      --center-y: ${rect.top + (rect.height / 2)}px;
    `);
});
.box {
  width: 50px;
  height: 50px;
  
  margin-left: 150px;
  
  background-color: blue;
  
  transform: translate(calc(var(--mouse-x) - var(--center-x)), calc(var(--mouse-y) - var(--center-y)));
}
<div class="box"></div>

This works, but it's not ideal and easily broken if anything else in the page changes. It also slows down with more elements, and I'd like it to be as fast as possible. It there a better way to do this? I'm fine using CSS/Vanilla JS.

like image 963
Jack Avatar asked Sep 10 '26 12:09

Jack


1 Answers

You don't have to use translate() please I would recommend you to use the left and top properties in CSS. They can help you position an element based on coordinates.

window.addEventListener('load', (e) => {
    const box = document.querySelector('.box');
    const rect = box.getBoundingClientRect();
    document.addEventListener('mousemove', (e) => {
    box.style.left = e.pageX + 'px';
    box.style.top = e.pageY + 'px';
});
});
.box {
  width: 50px;
  height: 50px;
  position:absolute;
  transform:translate(-50%,-50%);
  background-color: blue;
}
<div class="box"></div>

The transform: translate() property works relative to the size of the box but the left and top properties don't. It can also be much faster in some cases because in your code there was a lot of calculation going on. Whereas, this is straightforward.

like image 52
Code Fingers Avatar answered Sep 12 '26 02:09

Code Fingers



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!