<button>Find out more</button>
body {
  height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
}

@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');

@property --a {
  syntax: '<number>';
  initial-value: 0;
  inherits: false
}

@property --r {
  syntax: '<length-percentage>';
  initial-value: 0%;
  inherits: false
}

button {
  position: relative;
  overflow: hidden;
  color: #fff;
  background: 
    radial-gradient(circle at var(--x, 50%) var(--y, 50%), rgba(255, 255, 255, var(--a)) calc(var(--r) - 1px), transparent var(--r))
    #6200ee;
  padding: 1rem 2rem;
  font: 1.5rem 'Roboto', sans-serif;
  outline: 0;
  border: 0;
  border-radius: .25rem;
  box-shadow: 0 0 .5rem rgba(0, 0, 0, .3); /* black with 30% opacity */
  animation: a .6s linear;
  cursor: pointer;
}

button.ani { animation-name: fade, grow }

@keyframes fade { 0% { --a: .7 } }
@keyframes grow { to { --r: 200% } }
function removeAniFrom(_el) {
  if(_el.classList.contains('ani')) _el.classList.remove('ani')
}

addEventListener('click', e => {
  const _t = e.target;
  
  if(_t.tagName.toLowerCase() === 'button') {
    removeAniFrom(_t);
    
    const rect = _t.getBoundingClientRect();
    
    _t.style.setProperty('--x', `${e.clientX - rect.x}px`)
    _t.style.setProperty('--y', `${e.clientY - rect.y}px`)
    _t.classList.add('ani')
  }
}, false);

addEventListener('animationend', e => {  
  removeAniFrom(e.target)
}, false);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.