<hgroup>
    <h1>Ripple</h1>
    <h2>using animation.api</h2>
  </hgroup>
  
  <button>click me</button>
  <p></p>
  <button class=secondary>click me</button>
  <p></p>
  <button class=contrast>click me</button>
    
body{
  width:300px;
  margin: 0 auto;
  text-align: center;
}
   h1{
      font-weight:400;
      text-align:center;
    }
    h2{
      text-align:center;
      font-weight:500;
    }
    button{
      position:relative;
      width:200px;
      font-weight:400;
      text-transform: uppercase;
      margin:0 auto;
      box-shadow: 2px 3px 4px rgba(0,0,0,0.4);
      transition: all 200ms ease;
    }
    button:active{
      box-shadow:none;
    }
"use strict";
    
  function rippleEffect ( evt ) {

    let offset = this.getBoundingClientRect(), 
        ripple = document.createElement( 'div' ),
        aktOverflow = getComputedStyle( this ).overflow,
        light = `rgba(255,255,255,0)`,
        dark =  `rgba(255,255,255,.3)`,
        scale = Math.sqrt( 
          ( offset.width*offset.width ) + 
          ( offset.height*offset.height ) )/10;

    this.style.overflow = 'hidden';

    ripple.style = `
      width:20px;
      height:20px;
      border-radius: 50%;
      background: radial-gradient(circle, 
      ${dark} 0%, ${light} 5%, ${light} 7%, 
      ${dark} 13%, ${dark} 17%, ${light} 30%, 
      ${light} 35%, ${dark} 51%,${dark} 58%,
      ${light} 68%, ${light} 75%, ${dark} 100%);
      position: absolute;
      opacity: 0;
      transform-origin: 'center center';
      left: ${evt.clientX - offset.left -10}px;
      top: ${evt.clientY - offset.top -10}px;`

    this.prepend( ripple );

    let rippleAni = ripple.animate( [
        { transform: 'scale(0)', opacity:1 },
        { transform: `scale(${scale})`, opacity: .1 }
      ],
      { duration: 600}
    );

    Promise.resolve( rippleAni.finished )
      .then( () => { 
        ripple.remove();
        this.style.overflow=aktOverflow;
        }
      );
  }

  document.querySelectorAll( 'button' ).forEach( 
      el => el.addEventListener( 'mousedown', rippleEffect )
  )
     document.querySelectorAll( 'button' ).forEach( 
      el => el.addEventListener( 'click', ()=>console.log('click') )
  )

External CSS

  1. https://unpkg.com/@picocss/pico@latest/css/pico.min.css

External JavaScript

This Pen doesn't use any external JavaScript resources.