javascript – How to create ripple effect on click – `Material Design`

Question:

I am new to CSS animation and have been trying for the last hours to get the animation to work. Trying to understand the Material Design code but can't get it to work yet.

I'm talking about this effect: https://angular.io/ (menu effect). Basically, this is a click animation that spreads out in a circle from the mouse cursor.

It seems to boil down to these two lines:

transition: box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);
transition: box-shadow .4s cubic-bezier(.25,.8,.25,1),background-color .4s cubic-bezier(.25,.8,.25,1),transform .4s cubic-bezier(.25,.8,.25,1);   

PS: Maybe there is some jQuery code that implements this animation.

Free translation of How to create Ripple effect on Click – Material Design by @Antonin Cezard .

Answer:

A variation with CSS variables that are used to separate use of the transform property. Separating this property was necessary in order to correctly translate3d element ( translate3d ) and independently of the movement to scale ( scale ). Through JS, you can very conveniently manage these parameters.

From a performance point of view, this is a fairly good animation of this effect, since no insertions and deletions of nodes in the DOM are done and all work is done exclusively with the transform and opacity properties, which do not affect the composite layer, and therefore do not cause many page redrawings.

let span = document.querySelector('button span');

document.querySelector('button').addEventListener('click', function(e) {
  span.style.setProperty('--x', e.clientX - this.getBoundingClientRect().left - span.offsetWidth/2 + 'px');
  span.style.setProperty('--y', e.clientY - this.getBoundingClientRect().top - span.offsetHeight/2 + 'px');
  
  let scaleCount = 0,
      opacityCount = 1;
      
  const animationTime = 500;

  let scaleUp = setInterval(function() {
    scaleCount += 0.25;
    span.style.setProperty('--scale', scaleCount);
    
    opacityCount -= 0.05;
    span.style.opacity = opacityCount;
  }, animationTime / 20);

  setTimeout(function() {
    clearInterval(scaleUp);
    span.style.setProperty('--scale', 0);
  }, animationTime);
});
body {
  --x: 0px;
  --y: 0px;
  --scale: 0;
}

button {
  padding: 10px 20px;
  position: relative;
  overflow: hidden;
  border: 0;
  border-radius: 3px;
  background: linear-gradient(#c4e2fa, #c4effa);
  outline: 0;
  font: bold 17px arial;
  text-shadow: 0 0 3px rgba(0,0,0,0.3);
  color: #FFF;
}

button:hover {
  background: linear-gradient(#c4e2fa, #c4e8fa);
}

span {
  position: absolute;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.3);
  top: 0;
  left: 0;
  transform: translate3d(var(--x), var(--y), 0) scale(var(--scale));
}
<button>This is text<span></span></button>
Scroll to Top