DEV Community

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

Posted on

3 1

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

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)