CSS Gradient Button
A gradient button with a smooth hover shift, a visible keyboard focus ring and reduced-motion support — pure CSS.
Live preview Open in Playground
.btn-gradient {
--btn-from: #6d28d9; /* violet */
--btn-to: #be185d; /* deep pink */
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1.25rem;
border: 0;
border-radius: 0.75rem;
font: inherit;
font-weight: 600;
color: #fff;
cursor: pointer;
/* Twice as wide as the button, so we can slide it */
background-image: linear-gradient(120deg, var(--btn-from), var(--btn-to), var(--btn-from));
background-size: 200% 100%;
background-position: 0% 50%;
transition: background-position 0.5s ease, transform 0.15s ease;
}
.btn-gradient:hover {
background-position: 100% 50%;
}
.btn-gradient:active {
transform: translateY(1px);
}
.btn-gradient:focus-visible {
outline: 3px solid #f59e0b;
outline-offset: 3px;
}
.btn-gradient:disabled {
opacity: 0.55;
cursor: not-allowed;
}
@media (prefers-reduced-motion: reduce) {
.btn-gradient {
transition: none;
}
}Browsers can't animate between two background-image gradients — the change just snaps. The trick is to make the gradient wider than the button (background-size: 200%) and animate its position instead, which is animatable.
Why each part is there
- The gradient goes
from → to → from, so sliding it from0%to100%moves smoothly through the colours and ends on a matching colour — no hard edge. font: inheritstops the button from using the browser's default (often smaller) font.:focus-visibleshows a strong outline for keyboard users without showing it on every mouse click. Never remove focus styles without replacing them.- Both gradient colours keep white text above a 4.5:1 contrast ratio, the WCAG AA minimum for normal text. Check again if you change the colours.
prefers-reduced-motion: reduceturns the transition off for people who asked their operating system for less motion. The colour still changes — it just doesn't slide.
Use a real <button> for actions and an <a href> for navigation. The class works on both.
Usage
<button class="btn-gradient" type="button">Get started</button>
<!-- Different colours for one button -->
<a class="btn-gradient" href="/pricing" style="--btn-from: #0369a1; --btn-to: #4338ca;">
See pricing
</a>