Krzysztof Kaczyński
Krzysztof Kaczyński

Reputation: 5071

Why mouseEvent.offset is different for click in the same position

I am wondering why e.offsetX and e.offsetY are different for clicking in the same place. For the first click in a button e.offsetX and e.offsetY are correct but if you click a button before old ripple effect diapers than received event has incorrect e.offsetX and e.offsetY (always around 0). Because of this behavior my ripple effect has incorrect position if I click a button quickly many times.

const button = document.querySelector('button');

button.addEventListener('click', (e) => {
    const ripple = document.createElement('span');
    ripple.style.left = `${e.offsetX}px`;
    ripple.style.top = `${e.offsetY}px`;
    button.appendChild(ripple);
    window.setTimeout(() => {
        ripple.remove();
    }, 1000);
});
button {
  overflow: hidden;
    position: relative;
    width: 200px;
    height: 200px;
    border: 2px solid black;
}

button > span {
    position: absolute;
    background-color: green;
    border-radius: 50%;
    width: 1px;
    height: 1px;
    animation: ripple 1.0s linear infinite;
}
    
@keyframes ripple {
    0% {
        opacity: 0.7;
    }
    100% {
        opacity: 0;
        transform: scale(1000);
    }
}
<button>Test</button>

for those who prefer more JSFiddle

Upvotes: 1

Views: 1426

Answers (2)

dbramwell
dbramwell

Reputation: 1326

I think it's because you end up getting the offset of the ripple span, rather than the button. Adding a containing div like the below fixes it:

const button = document.querySelector('button');
const div = document.querySelector('div');
button.addEventListener('click', (e) => {
    const ripple = document.createElement('span');
    ripple.style.left = `${e.offsetX}px`;
    ripple.style.top = `${e.offsetY}px`;
    div.appendChild(ripple);
    window.setTimeout(() => {
        ripple.remove();
    }, 1000);
});
div {
  overflow: hidden;
    position: relative;
    width: 200px;
    height: 200px;
    border: 2px solid black;
}

button {
    width: 100%;
    height: 100%;
}

span {
    position: absolute;
    background-color: green;
    border-radius: 50%;
    width: 1px;
    height: 1px;
    animation: ripple 0.6s linear infinite;
}
    
@keyframes ripple {
    0% {
        opacity: 0.7;
    }
    100% {
        opacity: 0;
        transform: scale(1000);
    }
}
<div>
<button>Test</button>
</div>

Upvotes: 1

Konrad
Konrad

Reputation: 24671

offsetX and offsetY returns the position of event on the currentTarget not target. So when you click for the second time you are targeting the span you've just created. What I would have do is add pointer-events: none to the span css.

Ther other way is to use offsetX Wrong offsetX and offsetY on mousedown event of parent element

Upvotes: 2

Related Questions