<section class="flex scene">
  <div class="confetti">
    <figure class="confetti__image">
      <svg viewBox="-225 -225 450 450" role="presentational" />
    </figure>
    <button class="button confetti__button" type="button">
      <span class="button__text">
        click me
      </span>
    </button>
  </div>
</section>
$colors: (
  background: #d1d8e0,
  button: #3867d6,
  buttonText: #fff,
  buttonBorder: #26de81
);

.flex {
  align-items: center;
  display: flex;
  justify-content: center;
}

.scene {
  background-color: map-get($colors, background);
  height: 100vh;
}

.button {
  background: none;
  border: none;
  cursor: pointer;

  &:focus {
    outline: none;
  }

  &__text {
    background: map-get($colors, button);
    color: map-get($colors, buttonText);
    padding: 1em 3em;
    border-radius: 3em;
    font: 600 1rem/1 "Lato", sans-serif;
    white-space: nowrap;
    position: relative;
    z-index: 1;
    letter-spacing: 0.075em;
    border: 3px solid transparent;
    text-transform: uppercase;

    .button:focus & {
      // Can't think of anything that would look good
      // box-shadow: 0 0 2px 2px map-get($colors, buttonBorder);
      // text-decoration: underline;
    }
  }
}

.confetti {
  position: relative;

  &__image {
    position: absolute;
    width: 400px;
    height: 400px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
}
View Compiled
(function(){
  const svg = document.querySelector(".confetti__image svg");
  const button = document.querySelector(".confetti__button");
  const isAnimationOk = window.matchMedia('(prefers-reduced-motion: no-preference)').matches;

  const colors = [
    "#4b7bec", // blue
    "#fc5c65", // red
    "#fed330", // yellow
    "#26de81", // green
    "#2bcbba", // sea
    "#fd9644", // orange
    "#a55eea" // violet
  ];
  const positions = [-200, -175, -150, -125, -100, -75, -50, 50, 75, 100, 125, 150, 175, 200];
  const shapes = [
    "M -20 0 a 20 20 0 1 0 40 0 a 20 20 0 1 0 -40 0", // circle
    "M -20 0 a 20 20 0 1 0 40 0 Z", // semicircle
    "M -10 -10 H 20 V 20 H -10 Z", // square
    "M 0 -15 L 20 20 L -20 20 Z" // triangle
  ];
  const shapeCount = 16;
  const buttonTl = gsap.timeline();
  gsap.set(button, {
    transformOrigin: "50% 50%"
  });

  buttonTl.to(button, {
    scale: 0.975,
    repeat: 1,
    yoyo: true,
    duration: 0.15,
    ease: "Back.easeIn.config(1.5)"
  });
  buttonTl.pause();

  button.addEventListener("click", function (e) {
    buttonTl.play(0);

    var elements = [];

    for (let i = 0; i < shapeCount; i++) {
      var newElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
      newElement.setAttribute("d", gsap.utils.random(shapes));
      newElement.style.fill = gsap.utils.random(colors);
      svg.appendChild(newElement);
      elements.push(newElement);
    }

    function removeElements() {
      elements.forEach(shape => {
        svg.removeChild(shape);
      });
    }

    gsap.set(elements, {
      transformOrigin: "50% 50%",
      scale: "random(0.4, 1)",
    });
    gsap.to(elements, {
      onComplete: removeElements,
      keyframes: [{
        rotation: "random(-360, 360)",
        x: `random([${positions.join(",")}])`,
        y: `random([${positions.join(",")}])`,
        ease: "expo.out",
        duration: 3,
        stagger: {
          amount: 0.15
        }
      }, {
        opacity: 0,
        delay: -2.35,
        ease: "expo.out",
        duration: .5
      }]
    });
  });
}());

View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/lato-font/3.0.0/css/lato-font.min.css

External JavaScript

  1. https://unpkg.co/gsap@3/dist/gsap.min.js