20 CSS Animated Buttons11 / 20

CSS + JSMIT licensed

CSS Animated CTA Hero Button

A hero-section CTA button with a pulsing ring beacon, gradient text label, and particle burst on click — combining CSS animations with a lightweight JS particle emitter.

Published

Live Demo
Try it

The code

<div class="ab-11">
  <div class="ab-11__hero">
    <p class="ab-11__eyebrow">✦ Now in public beta</p>
    <h1 class="ab-11__title">The dev platform<br>built for speed.</h1>
    <p class="ab-11__sub">Deploy anywhere. Scale effortlessly. Ship today.</p>
    <div class="ab-11__wrap" id="ab-11-wrap">
      <button class="ab-11__btn" id="ab-11-btn">Start Building Free</button>
    </div>
    <p class="ab-11__note">No credit card · 50k free API calls included</p>
  </div>
</div>
.ab-11,
.ab-11 *,
.ab-11 *::before,
.ab-11 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ab-11 ::selection {
  background: #7c3aed;
  color: #fff;
}

.ab-11 {
  --beacon: #a78bfa;
  font-family: system-ui,sans-serif;
  background: #050510;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

.ab-11__hero {
  text-align: center;
  max-width: 520px;
}

.ab-11__eyebrow {
  font-size: .8rem;
  letter-spacing: .16em;
  color: #a78bfa;
  margin-bottom: 1rem;
  text-transform: uppercase;
}

.ab-11__title {
  font-size: clamp(2rem,5vw,3rem);
  font-weight: 900;
  color: #fff;
  line-height: 1.1;
  margin-bottom: 1rem;
}

.ab-11__sub {
  font-size: 1rem;
  color: #94a3b8;
  margin-bottom: 2rem;
  line-height: 1.6;
}

.ab-11__wrap {
  position: relative;
  display: inline-block;
  margin-bottom: 1rem;
}

.ab-11__wrap::before,
.ab-11__wrap::after {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 16px;
  border: 2px solid var(--beacon);
  opacity: 0;
  animation: ab-11-beacon 2s ease-out infinite;
}

.ab-11__wrap::after {
  animation-delay: .7s;
}

.ab-11__btn {
  position: relative;
  z-index: 1;
  padding: .95rem 2.6rem;
  font-size: 1.05rem;
  font-weight: 800;
  color: #fff;
  background: linear-gradient(135deg,#7c3aed,#2563eb);
  border: none;
  border-radius: 12px;
  cursor: pointer;
  outline: none;
  letter-spacing: .03em;
  box-shadow: 0 4px 24px rgba(124,58,237,.45);
  transition: filter .2s,transform .15s;
}

.ab-11__btn:hover {
  filter: brightness(1.12);
  transform: translateY(-2px);
}

.ab-11__btn:active {
  transform: translateY(0);
}

.ab-11__note {
  font-size: .75rem;
  color: #475569;
  margin-top: .5rem;
}

@keyframes ab-11-beacon {
  0% {
    transform: scale(1);
    opacity: .7;
  }

  100% {
    transform: scale(1.5);
    opacity: 0;
  }
}

.ab-11__particle {
  position: absolute;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  pointer-events: none;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  animation: ab-11-burst .7s ease-out forwards;
  will-change: transform,opacity;
}

@keyframes ab-11-burst {
  0% {
    transform: translate(-50%,-50%) translate(0,0) scale(1);
    opacity: 1;
  }

  100% {
    transform: translate(-50%,-50%) translate(var(--dx),var(--dy)) scale(0);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ab-11__wrap::before,
    .ab-11__wrap::after {
    animation: none;
  }
}
(function(){
  var wrap=document.getElementById('ab-11-wrap');
  var btn=document.getElementById('ab-11-btn');
  if(!btn||!wrap)return;
  var colours=['#a78bfa','#60a5fa','#34d399','#f472b6','#fbbf24','#fff'];
  var COUNT=12;
  btn.addEventListener('click',function(e){
    for(var i=0;i<COUNT;i++){
      var p=document.createElement('span');
      p.className='ab-11__particle';
      var angle=Math.random()*Math.PI*2;
      var dist=40+Math.random()*40;
      p.style.setProperty('--dx',Math.cos(angle)*dist+'px');
      p.style.setProperty('--dy',Math.sin(angle)*dist+'px');
      p.style.background=colours[Math.floor(Math.random()*colours.length)];
      p.style.left=e.offsetX+'px';
      p.style.top=e.offsetY+'px';
      wrap.appendChild(p);
      p.addEventListener('animationend',function(){this.remove()});
    }
  });
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Animated Button from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Animated CTA Hero Button
Source: https://codefronts.com/motion/css-animated-buttons/css-animated-cta-hero-button/

A hero-section CTA button with a pulsing ring beacon, gradient text label, and particle burst on click — combining CSS animations with a lightweight JS particle emitter.
## HTML
```html
<div class="ab-11">
  <div class="ab-11__hero">
    <p class="ab-11__eyebrow">✦ Now in public beta</p>
    <h1 class="ab-11__title">The dev platform<br>built for speed.</h1>
    <p class="ab-11__sub">Deploy anywhere. Scale effortlessly. Ship today.</p>
    <div class="ab-11__wrap" id="ab-11-wrap">
      <button class="ab-11__btn" id="ab-11-btn">Start Building Free</button>
    </div>
    <p class="ab-11__note">No credit card · 50k free API calls included</p>
  </div>
</div>
```
## CSS
```css
.ab-11,
.ab-11 *,
.ab-11 *::before,
.ab-11 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ab-11 ::selection {
  background: #7c3aed;
  color: #fff;
}

.ab-11 {
  --beacon: #a78bfa;
  font-family: system-ui,sans-serif;
  background: #050510;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

.ab-11__hero {
  text-align: center;
  max-width: 520px;
}

.ab-11__eyebrow {
  font-size: .8rem;
  letter-spacing: .16em;
  color: #a78bfa;
  margin-bottom: 1rem;
  text-transform: uppercase;
}

.ab-11__title {
  font-size: clamp(2rem,5vw,3rem);
  font-weight: 900;
  color: #fff;
  line-height: 1.1;
  margin-bottom: 1rem;
}

.ab-11__sub {
  font-size: 1rem;
  color: #94a3b8;
  margin-bottom: 2rem;
  line-height: 1.6;
}

.ab-11__wrap {
  position: relative;
  display: inline-block;
  margin-bottom: 1rem;
}

.ab-11__wrap::before,
.ab-11__wrap::after {
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 16px;
  border: 2px solid var(--beacon);
  opacity: 0;
  animation: ab-11-beacon 2s ease-out infinite;
}

.ab-11__wrap::after {
  animation-delay: .7s;
}

.ab-11__btn {
  position: relative;
  z-index: 1;
  padding: .95rem 2.6rem;
  font-size: 1.05rem;
  font-weight: 800;
  color: #fff;
  background: linear-gradient(135deg,#7c3aed,#2563eb);
  border: none;
  border-radius: 12px;
  cursor: pointer;
  outline: none;
  letter-spacing: .03em;
  box-shadow: 0 4px 24px rgba(124,58,237,.45);
  transition: filter .2s,transform .15s;
}

.ab-11__btn:hover {
  filter: brightness(1.12);
  transform: translateY(-2px);
}

.ab-11__btn:active {
  transform: translateY(0);
}

.ab-11__note {
  font-size: .75rem;
  color: #475569;
  margin-top: .5rem;
}

@keyframes ab-11-beacon {
  0% {
    transform: scale(1);
    opacity: .7;
  }

  100% {
    transform: scale(1.5);
    opacity: 0;
  }
}

.ab-11__particle {
  position: absolute;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  pointer-events: none;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  animation: ab-11-burst .7s ease-out forwards;
  will-change: transform,opacity;
}

@keyframes ab-11-burst {
  0% {
    transform: translate(-50%,-50%) translate(0,0) scale(1);
    opacity: 1;
  }

  100% {
    transform: translate(-50%,-50%) translate(var(--dx),var(--dy)) scale(0);
    opacity: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ab-11__wrap::before,
    .ab-11__wrap::after {
    animation: none;
  }
}
```

## JavaScript
```js
(function(){
  var wrap=document.getElementById('ab-11-wrap');
  var btn=document.getElementById('ab-11-btn');
  if(!btn||!wrap)return;
  var colours=['#a78bfa','#60a5fa','#34d399','#f472b6','#fbbf24','#fff'];
  var COUNT=12;
  btn.addEventListener('click',function(e){
    for(var i=0;i<COUNT;i++){
      var p=document.createElement('span');
      p.className='ab-11__particle';
      var angle=Math.random()*Math.PI*2;
      var dist=40+Math.random()*40;
      p.style.setProperty('--dx',Math.cos(angle)*dist+'px');
      p.style.setProperty('--dy',Math.sin(angle)*dist+'px');
      p.style.background=colours[Math.floor(Math.random()*colours.length)];
      p.style.left=e.offsetX+'px';
      p.style.top=e.offsetY+'px';
      wrap.appendChild(p);
      p.addEventListener('animationend',function(){this.remove()});
    }
  });
})();
```

How this works

Two layered ::before and ::after rings on the button wrapper animate outward via scale and opacity in a staggered loop (ab-11-beacon), creating the radar-ping effect popular on SaaS landing pages. The button itself carries an animated gradient border via a conic-gradient background on a ::before pseudo-element rotating behind the button at z-index: -1, clipped to a border zone using a nested padding trick.

The JS component spawns absolutely-positioned span particle elements on click, each assigned a random --dx/--dy CSS custom property that drives a short translate + opacity keyframe (ab-11-burst). This avoids JS-driven animation loops entirely — the browser handles all frame timing via the animation system. Particles are removed on animationend to prevent DOM build-up.

Make it yours

  • Change the beacon colour by updating --beacon on .ab-11__wrap — the ring pseudo-elements inherit from this variable.
  • Increase the particle count by raising the PARTICLE_COUNT constant in the JS from 12 to 20.
  • Slow the beacon pulse by editing animation-duration on .ab-11__wrap::before from 2s to 3.5s.
  • Use emoji or SVG icons as particles by setting the particle textContent in JS instead of leaving them as plain coloured dots.
  • Disable particles for a pure CSS version by removing the click event listener — the beacon and gradient border continue animating independently.

Gotchas — read before shipping

  • The conic-gradient spinning border technique requires the button to have position: relative; z-index: 0; overflow: hidden — removing any of these breaks the layering.
  • Particle spans are appended to the button wrapper and must have pointer-events: none to prevent them from capturing subsequent clicks mid-burst.
  • On low-end devices, spawning > 20 particles per click may cause a frame drop — cap the count and set will-change: transform, opacity on the particle class for GPU promotion.

Browser support

ChromeSafariFirefoxEdge
69+12.1+83+69+

Conic-gradient border trick requires Chrome 69+/Safari 12.1+/Firefox 83+.

Techniques used in this demo

Search CodeFronts

Loading…