20 CSS Animated Buttons07 / 20
CSS Moving Gradient CTA Button
An eye-catching call-to-action button with an infinite colour-cycling gradient background that shifts through violet, cyan, and rose — no JavaScript, no images.
Published
The code
<div class="ab-07">
<div class="ab-07__card">
<p class="ab-07__eyebrow">Limited Time Offer</p>
<h2 class="ab-07__heading">Start Your Free Trial</h2>
<p class="ab-07__body">14 days free, no credit card required. Cancel anytime with one click.</p>
<button class="ab-07__btn">Claim Your Free Trial →</button>
</div>
</div><div class="ab-07">
<div class="ab-07__card">
<p class="ab-07__eyebrow">Limited Time Offer</p>
<h2 class="ab-07__heading">Start Your Free Trial</h2>
<p class="ab-07__body">14 days free, no credit card required. Cancel anytime with one click.</p>
<button class="ab-07__btn">Claim Your Free Trial →</button>
</div>
</div>.ab-07,
.ab-07 *,
.ab-07 *::before,
.ab-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ab-07 ::selection {
background: #7c3aed;
color: #fff;
}
.ab-07 {
font-family: system-ui,sans-serif;
background: #0a0a14;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.ab-07__card {
background: #13131f;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 2.5rem 2rem;
max-width: 440px;
text-align: center;
}
.ab-07__eyebrow {
font-size: .72rem;
letter-spacing: .18em;
text-transform: uppercase;
color: #a78bfa;
margin-bottom: .75rem;
}
.ab-07__heading {
font-size: 1.8rem;
font-weight: 800;
color: #f1f5f9;
margin-bottom: .75rem;
}
.ab-07__body {
font-size: .9rem;
color: #94a3b8;
margin-bottom: 1.75rem;
line-height: 1.6;
}
.ab-07__btn {
display: inline-block;
padding: .9rem 2.4rem;
font-size: 1rem;
font-weight: 800;
color: #fff;
background: linear-gradient(90deg,#7c3aed,#06b6d4,#f43f5e,#7c3aed);
background-size: 300% 300%;
border: none;
border-radius: 12px;
cursor: pointer;
outline: none;
letter-spacing: .03em;
animation: ab-07-shift 4s ease infinite;
will-change: background-position;
box-shadow: 0 4px 20px rgba(124,58,237,.4);
transition: filter .2s,box-shadow .2s,transform .15s;
}
.ab-07__btn:hover {
filter: brightness(1.12);
box-shadow: 0 6px 32px rgba(124,58,237,.6);
transform: translateY(-2px);
}
.ab-07__btn:active {
transform: translateY(0);
filter: brightness(.95);
}
@keyframes ab-07-shift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@media (prefers-reduced-motion: reduce) {
.ab-07__btn {
animation: none;
background: linear-gradient(90deg,#7c3aed,#06b6d4);
}
}.ab-07,
.ab-07 *,
.ab-07 *::before,
.ab-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ab-07 ::selection {
background: #7c3aed;
color: #fff;
}
.ab-07 {
font-family: system-ui,sans-serif;
background: #0a0a14;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.ab-07__card {
background: #13131f;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 2.5rem 2rem;
max-width: 440px;
text-align: center;
}
.ab-07__eyebrow {
font-size: .72rem;
letter-spacing: .18em;
text-transform: uppercase;
color: #a78bfa;
margin-bottom: .75rem;
}
.ab-07__heading {
font-size: 1.8rem;
font-weight: 800;
color: #f1f5f9;
margin-bottom: .75rem;
}
.ab-07__body {
font-size: .9rem;
color: #94a3b8;
margin-bottom: 1.75rem;
line-height: 1.6;
}
.ab-07__btn {
display: inline-block;
padding: .9rem 2.4rem;
font-size: 1rem;
font-weight: 800;
color: #fff;
background: linear-gradient(90deg,#7c3aed,#06b6d4,#f43f5e,#7c3aed);
background-size: 300% 300%;
border: none;
border-radius: 12px;
cursor: pointer;
outline: none;
letter-spacing: .03em;
animation: ab-07-shift 4s ease infinite;
will-change: background-position;
box-shadow: 0 4px 20px rgba(124,58,237,.4);
transition: filter .2s,box-shadow .2s,transform .15s;
}
.ab-07__btn:hover {
filter: brightness(1.12);
box-shadow: 0 6px 32px rgba(124,58,237,.6);
transform: translateY(-2px);
}
.ab-07__btn:active {
transform: translateY(0);
filter: brightness(.95);
}
@keyframes ab-07-shift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@media (prefers-reduced-motion: reduce) {
.ab-07__btn {
animation: none;
background: linear-gradient(90deg,#7c3aed,#06b6d4);
}
}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 Moving Gradient CTA Button
Source: https://codefronts.com/motion/css-animated-buttons/css-moving-gradient-cta-button/
An eye-catching call-to-action button with an infinite colour-cycling gradient background that shifts through violet, cyan, and rose — no JavaScript, no images.
## HTML
```html
<div class="ab-07">
<div class="ab-07__card">
<p class="ab-07__eyebrow">Limited Time Offer</p>
<h2 class="ab-07__heading">Start Your Free Trial</h2>
<p class="ab-07__body">14 days free, no credit card required. Cancel anytime with one click.</p>
<button class="ab-07__btn">Claim Your Free Trial →</button>
</div>
</div>
```
## CSS
```css
.ab-07,
.ab-07 *,
.ab-07 *::before,
.ab-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ab-07 ::selection {
background: #7c3aed;
color: #fff;
}
.ab-07 {
font-family: system-ui,sans-serif;
background: #0a0a14;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.ab-07__card {
background: #13131f;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 2.5rem 2rem;
max-width: 440px;
text-align: center;
}
.ab-07__eyebrow {
font-size: .72rem;
letter-spacing: .18em;
text-transform: uppercase;
color: #a78bfa;
margin-bottom: .75rem;
}
.ab-07__heading {
font-size: 1.8rem;
font-weight: 800;
color: #f1f5f9;
margin-bottom: .75rem;
}
.ab-07__body {
font-size: .9rem;
color: #94a3b8;
margin-bottom: 1.75rem;
line-height: 1.6;
}
.ab-07__btn {
display: inline-block;
padding: .9rem 2.4rem;
font-size: 1rem;
font-weight: 800;
color: #fff;
background: linear-gradient(90deg,#7c3aed,#06b6d4,#f43f5e,#7c3aed);
background-size: 300% 300%;
border: none;
border-radius: 12px;
cursor: pointer;
outline: none;
letter-spacing: .03em;
animation: ab-07-shift 4s ease infinite;
will-change: background-position;
box-shadow: 0 4px 20px rgba(124,58,237,.4);
transition: filter .2s,box-shadow .2s,transform .15s;
}
.ab-07__btn:hover {
filter: brightness(1.12);
box-shadow: 0 6px 32px rgba(124,58,237,.6);
transform: translateY(-2px);
}
.ab-07__btn:active {
transform: translateY(0);
filter: brightness(.95);
}
@keyframes ab-07-shift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@media (prefers-reduced-motion: reduce) {
.ab-07__btn {
animation: none;
background: linear-gradient(90deg,#7c3aed,#06b6d4);
}
}
```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 Moving Gradient CTA Button
Source: https://codefronts.com/motion/css-animated-buttons/css-moving-gradient-cta-button/
An eye-catching call-to-action button with an infinite colour-cycling gradient background that shifts through violet, cyan, and rose — no JavaScript, no images.
## HTML
```html
<div class="ab-07">
<div class="ab-07__card">
<p class="ab-07__eyebrow">Limited Time Offer</p>
<h2 class="ab-07__heading">Start Your Free Trial</h2>
<p class="ab-07__body">14 days free, no credit card required. Cancel anytime with one click.</p>
<button class="ab-07__btn">Claim Your Free Trial →</button>
</div>
</div>
```
## CSS
```css
.ab-07,
.ab-07 *,
.ab-07 *::before,
.ab-07 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ab-07 ::selection {
background: #7c3aed;
color: #fff;
}
.ab-07 {
font-family: system-ui,sans-serif;
background: #0a0a14;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 2rem;
}
.ab-07__card {
background: #13131f;
border: 1px solid rgba(255,255,255,.07);
border-radius: 16px;
padding: 2.5rem 2rem;
max-width: 440px;
text-align: center;
}
.ab-07__eyebrow {
font-size: .72rem;
letter-spacing: .18em;
text-transform: uppercase;
color: #a78bfa;
margin-bottom: .75rem;
}
.ab-07__heading {
font-size: 1.8rem;
font-weight: 800;
color: #f1f5f9;
margin-bottom: .75rem;
}
.ab-07__body {
font-size: .9rem;
color: #94a3b8;
margin-bottom: 1.75rem;
line-height: 1.6;
}
.ab-07__btn {
display: inline-block;
padding: .9rem 2.4rem;
font-size: 1rem;
font-weight: 800;
color: #fff;
background: linear-gradient(90deg,#7c3aed,#06b6d4,#f43f5e,#7c3aed);
background-size: 300% 300%;
border: none;
border-radius: 12px;
cursor: pointer;
outline: none;
letter-spacing: .03em;
animation: ab-07-shift 4s ease infinite;
will-change: background-position;
box-shadow: 0 4px 20px rgba(124,58,237,.4);
transition: filter .2s,box-shadow .2s,transform .15s;
}
.ab-07__btn:hover {
filter: brightness(1.12);
box-shadow: 0 6px 32px rgba(124,58,237,.6);
transform: translateY(-2px);
}
.ab-07__btn:active {
transform: translateY(0);
filter: brightness(.95);
}
@keyframes ab-07-shift {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
@media (prefers-reduced-motion: reduce) {
.ab-07__btn {
animation: none;
background: linear-gradient(90deg,#7c3aed,#06b6d4);
}
}
```How this works
The shifting gradient effect is achieved by setting a background-size: 300% 300% on the button and animating background-position with a @keyframes ab-07-shift loop that moves the position from 0% 50% to 100% 50% and back. Because the gradient is three times wider than the visible area, each position reveals a different colour region of the gradient, creating the illusion of a continuously colour-cycling background. The gradient uses stops of violet → cyan → rose → violet so the loop is seamless.
A filter: brightness(1.1) on :hover provides immediate visual feedback without interrupting the gradient animation. The button also carries a matching coloured box-shadow that breathes with the gradient using a second animation applied to the shadow spread. All animation uses only background-position and box-shadow — the former is GPU-accelerated in modern browsers when paired with will-change: background-position.
Make it yours
- Swap the colour palette by editing the gradient stops — try
#f97316, #ec4899, #8b5cf6for a sunset feel. - Speed up or slow the cycle by changing the
animation-durationon.ab-07__btn(default4s; try2sfor energetic or8sfor ambient). - Pause the animation on hover by adding
animation-play-state: pausedto the:hoverrule — this freezes the gradient and creates a "snapshot" effect. - Use a diagonal sweep by changing the gradient direction from
90degto135degand keeping the same position animation. - Add a shimmer overlay by placing a semi-transparent
::afterpseudo-element with alinear-gradient(transparent 40%, rgba(255,255,255,.08) 50%, transparent 60%)animated across the button.
Gotchas — read before shipping
background-positionanimations are not always fully GPU-composited — on battery-constrained devices the animation may consume measurable power; consider pausing withIntersectionObserverwhen off-screen.- Some older WebKit versions render a visible seam at the gradient loop point — ensure the first and last gradient stop colours match (the demo uses violet at both ends) to close the loop.
- Firefox 68 and below do not support animating
background-positionsmoothly with percentage values on gradients — use explicit pixel positions as a fallback for legacy support.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 26+ | 9+ | 16+ | 26+ |
background-position animation is universally supported; behaviour is consistent across modern browsers.