DEV Community

Cover image for Ripple Effect using JS animation api
Frank Wisniewski
Frank Wisniewski

Posted on

Ripple Effect using JS animation api

see comments in Source Code

<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <title>Ripple sample</title>
  <!-- 
    Pico.css • Minimal CSS Framework for semantic HTML
  -->
  <link rel="stylesheet"
    href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
  <style>
    h1{
      font-weight:400;
      text-align:center;
    }
    h2{
      text-align:center;
      font-weight:500;
    }
    button{
      /*
        it is important to use position: relative
      */
      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;
    }
  </style>

</head>
<body class=container>

  <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>

<script>
  "use strict";

  function rippleEffect ( evt ) {
    // get Coordinates from current Button
    let offset = this.getBoundingClientRect(), 
        // create the ripple div
        ripple = document.createElement( 'div' ),
        // save the overflow style from current Button
        aktOverflow = getComputedStyle( this ).overflow,
        // set colors for ripple
        light = `rgba(255,255,255,0)`,
        dark =  `rgba(255,255,255,.3)`,
        // calc the diagonal width from element
        scale = Math.sqrt( 
          ( offset.width*offset.width ) + 
          ( offset.height*offset.height ) )/10;
    // set overflow Button 
    this.style.overflow = 'hidden';
    // style the ripple Element
    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;`
    // inject ripple in button
    this.prepend( ripple );
    // create the animate object
    let rippleAni = ripple.animate( [
        { transform: 'scale(0)', opacity:1 },
        { transform: `scale(${scale})`, opacity: .1 }
      ],
      { duration: 600}
    );
    // kill the ripple when animation finished
    Promise.resolve( rippleAni.finished )
      .then( () => { 
        ripple.remove();
        this.style.overflow=aktOverflow;
        }
      );
  }

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

</script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

TRY IT

Oldest comments (0)