La idea
Cuando haces clic, sabemos en qué píxel exacto ocurrió. Ahí creamos un círculo diminuto y dejamos que el CSS lo escale hasta hacerse grande mientras se desvanece. Al terminar, lo borramos.
c.style.left = (e.clientX - r.left) + 'px'; c.style.top = (e.clientY - r.top) + 'px';
El CSS
El botón necesita overflow:hidden (para que la onda no se salga) y position:relative. El círculo escala hasta 9 veces su tamaño.
.onda{ position:relative; overflow:hidden; }
.onda .circulo{
position:absolute; width:20px; height:20px; border-radius:50%;
background:var(--papel); opacity:.5;
transform:translate(-50%,-50%) scale(0);
animation:crecer .6s ease-out forwards;
}
@keyframes crecer{
to{ transform:translate(-50%,-50%) scale(9); opacity:0; }
}
El JavaScript
boton.addEventListener('click', e => {
const r = boton.getBoundingClientRect();
const c = document.createElement('span');
c.className = 'circulo';
c.style.left = (e.clientX - r.left) + 'px';
c.style.top = (e.clientY - r.top) + 'px';
boton.appendChild(c);
setTimeout(() => c.remove(), 600);
});
Por qué se siente bien
El ripple da feedback: confirma que tu clic “llegó” y desde dónde. Ese pequeño detalle hace que una interfaz se sienta responsiva y física, no muerta.