Button ripple effect
by phloe
HTML
<button id="button">Click here</button>
CSS
button {
--mouse-x: 0px;
--mouse-y: 0px;
padding: 10px 20px;
border: 0;
color: #FFF;
background: red;
text-transform: uppercase;
position: relative;
overflow: hidden;
box-sizing: border-box;
}
button::after {
content: "";
display: block;
position: absolute;
top: -15px;
left: -15px;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: #FFF;
opacity: 0;
transform: translate(var(--mouse-x, 0px), var(--mouse-y, 0px)) scale(0.5);
}
button:focus:not(:focus-visible) {
outline: none;
}
button:active::after {
opacity: 1;
transition: 0.2s opacity ease-in-out;
}
.ripple::after {
animation: 0.75s button ease-in-out;
}
@keyframes button {
0% {
opacity: 0.5;
}
100% {
transform: translate(var(--mouse-x, 0px), var(--mouse-y, 0px)) scale(10);
opacity: 0;
}
}
JavaScript
let rippling = false;
function resetRipple() {
button.removeEventListener("animationend", resetRipple);
button.classList.remove("ripple");
rippling = false;
}
button.addEventListener("mousedown", function(event) {
if (rippling) {
resetRipple();
void button.offsetWidth;
}
rippling = true;
const { left, top } = button.getBoundingClientRect();
button.style.setProperty("--mouse-x", event.clientX - left + "px");
button.style.setProperty("--mouse-y", event.clientY - top + "px");
button.addEventListener("animationend", resetRipple);
button.classList.add("ripple");
});