Disco CSS button
Iridescent flowing disco gradient with a shine sweep. Hover, click and tab to it to see every state.
CSS
@import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;500;600;700;800&display=swap');
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: .5em;
padding: 14px 28px;
font-family: 'Syne', sans-serif;
font-size: 16px;
font-weight: 800;
line-height: 1.2;
color: #1e1b4b;
background: linear-gradient(90deg, #f0abfc 0%, #93c5fd 25%, #fde68a 50%, #f9a8d4 75%, #a5f3fc 100%);
background-size: 200% 200%;
border: 1px solid rgba(255, 255, 255, .6999999999999999555910790149937383830547332763671875);
border-radius: 999px;
box-shadow: 0 10px 30px -10px rgba(167, 139, 250, .8000000000000000444089209850062616169452667236328125), inset 0 1px 0 0 rgba(255, 255, 255, .8000000000000000444089209850062616169452667236328125);
position: relative;
overflow: hidden;
isolation: isolate;
cursor: pointer;
text-decoration: none;
white-space: nowrap;
-webkit-tap-highlight-color: transparent;
transition: transform 200ms cubic-bezier(.2,.8,.2,1), box-shadow 200ms cubic-bezier(.2,.8,.2,1), filter 200ms cubic-bezier(.2,.8,.2,1);
animation: btn-flow 4s ease-in-out infinite alternate;
}
.btn__icon {
display: inline-block;
transition: transform 200ms cubic-bezier(.2,.8,.2,1);
}
.btn::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(110deg, transparent 35%, rgba(255, 255, 255, .45) 50%, transparent 65%);
transform: translateX(-120%);
transition: transform .7s ease;
pointer-events: none;
}
.btn:hover {
transform: translateY(-3px);
filter: brightness(1.0500000000000000444089209850062616169452667236328125);
box-shadow: 0 13px 36px -10px rgba(167, 139, 250, .8000000000000000444089209850062616169452667236328125), inset 0 1px 0 0 rgba(255, 255, 255, .8000000000000000444089209850062616169452667236328125), 0 0 22px 0 rgba(196, 181, 253, .59999999999999997779553950749686919152736663818359375);
}
.btn:hover::after {
transform: translateX(120%);
}
.btn:hover .btn__icon {
transform: translateX(3px);
}
.btn:active {
transform: translateY(1px) scale(0.979999999999999982236431605997495353221893310546875);
box-shadow: 0 9px 30px -10px rgba(167, 139, 250, .8000000000000000444089209850062616169452667236328125), inset 0 1px 0 0 rgba(255, 255, 255, .8000000000000000444089209850062616169452667236328125);
transition-duration: 100ms;
}
.btn:focus-visible {
outline: 3px solid #f0abfc;
outline-offset: 3px;
}
@keyframes btn-flow {
from {
background-position: 0% 50%;
}
to {
background-position: 100% 50%;
}
}
@media (prefers-reduced-motion: reduce) {
.btn,
.btn::after,
.btn__icon {
transition: none;
animation: none;
}
}
HTML
<button class="btn" type="button">
Dance
<span class="btn__icon" aria-hidden="true">★</span>
</button>
How this button is built
- Background: a 5-stop
linear-gradient()at 90° (#f0abfc → #93c5fd → #fde68a → #f9a8d4 → #a5f3fc). - Type: Syne, weight 800, 16px, in #1e1b4b.
- Shape: a fully rounded pill shape with 14px × 28px padding, plus a 1px solid border.
- Depth: a coloured glow and an inset highlight along the edge.
- Effects: a light sweep (
::after) that slides across on hover and a gradient that flows continuously with@keyframes. - Interaction: on hover it lifts 3px, brightens slightly, glows and nudges its icon, and it squishes slightly when clicked, with 200ms transitions.
- Accessibility: a visible
:focus-visiblering for keyboard users, and all motion turns off underprefers-reduced-motion.
How to use it
- Copy the CSS into your stylesheet. The
@importline loads the Syne font from Google Fonts. Move it to the top of your file, or drop it if you already load the font. - Paste the HTML where you want the button. It works on
<button>,<a>and<input type="submit">. - Change the label, or rename the
.btnclass if it clashes with your framework. Want a different colour or size? Open it in the editor, change it visually, and copy the new code.