<a href="https://youtu.be/may0MddSzNc" target="_blank" data-keyframers-credit style="color: #000"></a>
<script src="https://codepen.io/shshaw/pen/QmZYMG.js"></script>

<button class="like-button">
  <div class="like-wrapper">
    <div class="ripple"></div>
    <svg class="heart" width="24" height="24" viewBox="0 0 24 24">
      <path d="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"></path>
    </svg>
    <div class="particles" style="--total-particles: 6">
      <div class="particle" style="--i: 1; --color: #7642F0"></div>
      <div class="particle" style="--i: 2; --color: #AFD27F"></div>
      <div class="particle" style="--i: 3; --color: #DE8F4F"></div>
      <div class="particle" style="--i: 4; --color: #D0516B"></div>
      <div class="particle" style="--i: 5; --color: #5686F2"></div>
      <div class="particle" style="--i: 6; --color: #D53EF3"></div>
    </div>
  </div>
</button>
*, *:before, *:after {
  position: relative;
  box-sizing: border-box;
}

:root {
  --color-bg: #FDF1F2;
  --color-heart: #EA442B;
  --easing: cubic-bezier(.7,0,.3,1);
  --duration: .5s;
}

html, body {
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.like-button {
  font-size: 35vmin;
  appearance: none;
  border: none;
  border-radius: 50%;
  background: white;
  
  width: 1em;
  height: 1em;
  padding: 0;
  margin: 0;
  outline: none;
  z-index: 2;
  transition: transform var(--duration) var(--easing);
  cursor: pointer;
  
  &:before {
    z-index: -1;
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    box-shadow: 0 .3em 0.6em rgba(black, 0.3);
    border-radius: inherit;
    transition: inherit;
  }
  
  &:after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #fff;
    border-radius: inherit;
    z-index: -1;
  }
  
  &:active {
    &:before {
      animation: depress-shadow var(--duration) var(--easing) both;
    }
  }
  
  &:focus:after {
    animation: depress var(--duration) var(--easing) both;
  }
  
  @keyframes depress {
    from, to {
      transform: none;
    }
    50% {
      transform: translateY(5%) scale(0.9);
    }
  }
  
  @keyframes depress-shadow {
    from, to {
      transform: none;
    }
    50% {
      transform: scale(0.5);
    }
  }
}

.like-wrapper {
  display: grid;
  align-items: center;
  justify-content: center;
  z-index: 1;
  
  > * { 
    margin: auto;
    grid-area: 1 / 1; 
  }
}

.heart {
  width: .5em;
  height: .5em;
  display: block;
  
  > path {
    stroke: var(--color-heart);
    stroke-width: 2;
    fill: transparent;
    transition: fill var(--duration) var(--easing);

    .like-button:focus & {
      fill: var(--color-heart); 
    }
  }
  
  transform-origin:  center 80%;
  
  .like-button:focus & {
    animation: heart-bounce var(--duration) var(--easing);
    @keyframes heart-bounce {
      40% { transform: scale(0.7); }
      0%, 80%, 100% { transform: scale(1); }
    }
  }
}

/* Added wrapper to prevent layout jank with resizing particles */
.particles {
  width: 1px;
  height: 1px;
}

.particle {
  position: absolute;
  top: 0;
  left: 0;
  height: .1em;
  width: .1em;
  border-radius: .05em;
  background-color: var(--color);
  --percentage: calc( var(--i) / var(--total-particles) );
  --Θ: calc( var(--percentage) * 1turn );
  transform: translate(-50%, -50%) rotate( var(--Θ) ) translateY(0) scaleY(0);
  transition: all var(--duration) var(--easing);
  
  .like-button:focus & {
    animation: particles-out calc(var(--duration) * 1.2) var(--easing) forwards;
    
    @keyframes particles-out {
      50% {
        height: .3em;
      }
      50%, 60% {
        height: .3em;
        transform:
          translate(-50%, -50%) 
          rotate( var(--Θ) )
          translateY(.8em)
          scale(1)
          ;
      }
      60% {
        height: .2em;
      }
      100% { 
        transform:
          translate(-50%, -50%) 
          rotate( var(--Θ) )
          translateY(1em)
          scale(0)
          ;
      }
    }
  }
}

.ripple {
  height: 1em;
  width: 1em;
  border-radius: 50%;
  overflow: hidden;
  z-index: 1;
  
  &:before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border: .4em solid var(--color-heart);
    border-radius: inherit;
    transform: scale(0);
  }
  
  .like-button:focus & {
    &:before {
      animation: ripple-out var(--duration) var(--easing);
      @keyframes ripple-out {
        from { transform: scale(0); }
        to { transform: scale(5); }
      }
    }
  }
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: var(--color-bg);
}

/* Reset the animation when clicking again! */
.like-button:focus {
  pointer-events: none;
  cursor: normal;
}
View Compiled
// Nope
// ...except to show the animation on load
let b = document.querySelector('button');
setTimeout(()=>b.focus(), 100);
setTimeout(()=>b.blur(), 1000);

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.