After-click animation using only CSS
26 Aug 2023

We are interested to emulate the after-click animation effect from Ant Design’s Button page. We can see that whenever we click on the button, there is a subtle radiate effect. In this post we will see how we can achieve it using just CSS and then TailwindCSS.

Background

I believed it is not as well-known to create an after-click animation using just pure CSS. CSS does provides the :hover and :active selectors for developers to style when we mouse hover and mouse press on the button, and it is not obvious how we can provide an animation after a click event. At least for me, I didn’t know how to do it. A quick google search led me to this demo from w3schools which gave me a huge help on how to achieve it.

CSS only implementation

Here is the code with CSS.

.app-btn {
  position: relative;
  border-radius: 9999px;
  border: 1px solid #60a5fa;
  background: white;
  padding: 0.5rem 1rem;
  font-weight: 500;
  color: #60a5fa;
  transition:
    color 300ms ease-out,
    border-color 300ms ease-out,
    background-color 300ms ease-out;
  transform-style: preserve-3d;
}

.app-btn:hover {
  border-color: #93c5fd;
  background-color: #eff6ff;
  color: #93c5fd;
}

.app-btn:active {
  border-color: #2563eb;
  background-color: #d2e3fc;
  color: #2563eb;
}

.app-btn:before {
  content: "";
  border-radius: 9999px;
  background-color: #60a5fa;
  position: absolute;
  opacity: 0;
  z-index: -10;
  inset: -8px;
  transition: all 300ms ease-out;
  transform: translateZ(-1px);
}

.app-btn:active:before {
  inset: 0;
  opacity: 1;
  transition: none;
}

Explanation of the CSS code

The general idea is to use the pseudo element (:before or :after) as an extra layer below (using a negative z-index) the button layer, then animate the CSS inset property to negative to have the pseudo element scale up and at the same time animate the opacity to achieve the radiate effect. The question is how do we trigger “after-click” here? The trick is in the :active:before selector, where we set the start of the animation and also more importantly, setting the transition to none so as not to trigger any animation going from “non-active” to “active”. And once the user released the mouse on the button, we go from “active” to “non-active” and this is where we want the animation to start.

There is also an unusual use of transform-style: preserve-3d and transform: translateZ(-1px) in the CSS code above. This is to fix an issue of z-index-ed pseudo element not showing up. There is a stackoverflow issue about this.

TailwindCSS implementation

Here is the code using TailwindCSS classes for those interested.

.app-btn {
  @apply before:absolute 
         before:inset-[-8px] 
         before:-z-10 
         before:rounded-full 
         before:bg-blue-300 
         before:opacity-0 
         before:transition-all 
         before:duration-300 
         before:ease-out 
         before:content-['']
         active:before:inset-0 
         active:before:opacity-100 
         active:before:transition-none
         relative
         rounded-full
         border
         border-blue-500
         bg-white
         px-4 py-2
         font-medium
         text-blue-500
         transition-colors duration-300
         hover:border-blue-400 
         hover:bg-blue-50 
         hover:text-blue-400
         active:border-blue-600 
         active:bg-blue-100 
         active:text-blue-600;
  transform-style: preserve-3d;
}
.app-btn:before {
  transform: translateZ(-1px);
}

Note that transform-style: preserve-3d and transform: translateZ(-1px) is not provided by TailwindCSS, so we might want to add it into the our own custom utility layer.

Button in action

Notice the subtle radiate effect after clicking on the button.

Conclusion

Doing after-click animation in CSS is not as obvious and intuitive as it seems. However understanding that we can control between the event lifecycle from “non-active” to “active” and “active” to “non-active” separately is essential to create the behavior that we want in this use-case.