Sparking animation for Button I just came through a GitHub repo, which has an amazing animation for Button in Android.

So, I thought why not make that for web buttons too.

And I started designed that.

Here is my repo for the same.

Here is my code:



let icons = $('.magic')

for (let i = 0; i &lt; icons.length; ++i) {
    icons[i].onclick = function (element) {
        icons[i].classList.toggle('enabled');
    }
}
.magic {
    display: inline-block;
    margin: 50px;
    position: relative;
  }

  .magic i {
    color: orange;
    filter: grayscale(100%);
    position: relative;
    animation: disable 0.5s forwards;
  }

  .enabled i {
    animation: enable 1s forwards;
  }

  .magic::before {
    content: "";
    top:calc(50% - 45px);
    left:calc(50% - 45px);
    width: 90px;
    height: 90px;
    position: absolute;
    border-color: orange;
    border-style: solid;
    border-width: 45px;
    border-radius: 50%;
    transform: scale(0);
    box-sizing: border-box;
  }

  .enabled::before {
    transition:
      transform 0.5s,
      border-width 0.5s 0.2s;
    transform: scale(1);
    border-width: 0px;
  }

  .magic::after,
  .magic i::after {
    content: "";
    position: absolute;
    top: calc(50% - 80px);
    left: calc(50% - 80px);
    height: 160px;
    width: 160px;
    background:
      radial-gradient(circle, red 50%, transparent 60%),
      radial-gradient(circle, red 50%, transparent 60%),
      radial-gradient(circle, red 50%, transparent 60%),
      radial-gradient(circle, red 50%, transparent 60%),
      radial-gradient(circle, orange 50%, transparent 60%),
      radial-gradient(circle, orange 50%, transparent 60%),
      radial-gradient(circle, orange 50%, transparent 60%),
      radial-gradient(circle, orange 50%, transparent 60%);

    background-position:  
      calc(50% - 50px) calc(50% - 50px),
      calc(50% - 50px) calc(50% + 50px),
      calc(50% + 50px) calc(50% - 50px),
      calc(50% + 50px) calc(50% + 50px),
      calc(50% - 0px) calc(50% - 70px),
      calc(50% - 70px) calc(50% - 0px),
      calc(50% - 0px) calc(50% + 70px),
      calc(50% + 70px) calc(50% - 0px);
    background-size: 16px 16px;
    background-repeat: no-repeat;
    border-radius:50%;
    transform: scale(0);
  }

  .magic i:after {
    background-size: 10px 10px;
    transform: rotate(10deg) scale(0);
  }

  .enabled::after {
    transition: 
      transform 0.5s 0.5s,
      opacity 0.4s 1s,
      background-size 0.4s 1s;

    transform: scale(1);
    opacity: 0;
    background-size: 0 0;
  }

  .enabled i:after {
    transition: 
      transform 0.5s 0.5s,
      opacity 0.4s 0.8s,
      background-size 0.4s 0.8s;

    transform: rotate(10deg) scale(1);
    opacity: 0;
    background-size: 0 0;
  }

  @keyframes enable {
    50% {
      filter: grayscale(100%);
      transform: scale(0);
    }
    51% {
      filter: grayscale(0%)
    }
    90% {
        transform: scale(1.3)
    }
    100% {
      filter: grayscale(0%);
      transform: scale(1);
    }
  }

  @keyframes disable {
      50% {
          filter: grayscale(0%);
          transform: scale(1.3);
      }
      100% {
          transform: scale(1);
      }

  }
&lt;span class="magic"&gt;
    &lt;i class="fas fa-star fa-5x"&gt;&lt;/i&gt;
&lt;/span&gt;

&lt;span class="magic"&gt;
    &lt;i class="fas fa-bell fa-5x"&gt;&lt;/i&gt;
&lt;/span&gt;

&lt;span class="magic"&gt;
    &lt;i class="fas fa-bolt fa-5x"&gt;&lt;/i&gt;
&lt;/span&gt;

&lt;span class="magic"&gt;
    &lt;i class="fas fa-check fa-5x"&gt;&lt;/i&gt;
&lt;/span&gt;

&lt;span class="magic"&gt;
    &lt;i class="fas fa-thumbs-up fa-5x"&gt;&lt;/i&gt;
&lt;/span&gt;

&lt;!-- Other stuff --&gt;
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"&gt;&lt;/script&gt;
&lt;link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"&gt;




What do you reckon? Is there anything I can improve either in the animation or in the code?
I'd like to suggest the opposite of Sᴀᴍ Onᴇᴌᴀ: Since you are using jQuery for selecting only, you can drop it altogether.

const icons = $(".magic");


becomes either

const icons = document.getElementsByClassName("magic");


or

const icons = document.querySelectorAll(".magic");


However you shouldn't use on... properties to assign event handlers. on... properties can only hold a single handler so if you or another script would attempt to assign another click handler then they'd overwrite each other. Instead use addEventListener.

Alternatively to avoid assigning seperate event handlers to each icon you could use event delegation. This means assign an single event handler to a surrounding element (or simply document) and check the target element:

document.addEventListener("click", function (event) {
  if (event.target.classList.contains("magic")) {
    event.target.classlist.toggle("enabled");
  }
};


Finally you could avoid using JavaScript altogether by using an HTML element that has the toggle functionality built in: a checkbox:

&lt;label class="magic-wrapper"&gt;
  &lt;input type="checkbox"&gt;&lt;span class="magic"&gt;&lt;i class="fas fa-star fa-5x"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;/label&gt;


Hide the actual checkbox with:

.magic-wrapper &gt; input {
  opacity: 0;
  position: absolute;
}


(This is more accessable than just using display: none;)

And replace the selector .enabled with input:checked + .magic in the CSS.

Complete example: https://jsfiddle.net/rhy6gfn4/



A small points about the CSS: 

You should select not just .enabled but use .magic.enabled, because then it's more obvious that these rules belong to the animated icons. Also "enabled" is a common class name and you don't want those styles apply to unrelated elements.

It would be a tiniest bit more performant to select the i elements using .magic &gt; i and not just .magic i.