Last active
January 3, 2024 09:06
-
-
Save AlexIsMaking/26f3893847b9f2ec297885c49428ef8e to your computer and use it in GitHub Desktop.
Glowy Border Shimmer Button React component with Tailwind CSS styling. Based on @jh3yy's button - https://codepen.io/jh3y/pen/vYbyKeL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*, | |
*:after, | |
*:before { | |
box-sizing: border-box; | |
} | |
:root { | |
--saturation: 20%; | |
--transition: 0.15s; | |
--glow: hsl(var(--hue, 150) 80% 70% / var(--alpha, 1)); | |
--border-radius: calc(var(--radius) * 1px); | |
--border-width: calc(var(--thickness) * 1px); | |
--active: 0; | |
--glow-spread: calc(var(--spread) * 1deg); | |
} | |
.glow-button { | |
--bg: radial-gradient(40% 50% at center 100%, hsl(var(--hue) var(--saturation) 72% / 0.15), transparent), | |
radial-gradient(80% 100% at center 120%, hsl(var(--hue) var(--saturation) 70% / 0.2), transparent), hsl(260 0% 2%); | |
background: var(--bg); | |
place-items: center; | |
border-radius: var(--border-radius); | |
box-shadow: 0 0.025em 0.4em -0.02em hsl(0 0% 100% / 0.25), 0 0.05em 0 0 hsl(260 0% 50%) inset, | |
0 -0.05em 0 0 hsl(260 0% 0%) inset; | |
transition: box-shadow var(--transition), scale var(--transition), background var(--transition); | |
scale: calc(1 + (var(--active) * 0.025)); | |
} | |
/* Feint border */ | |
.glow-button::before { | |
--saturation: 90%; | |
content: ""; | |
position: absolute; | |
inset: 0; | |
border: 1px solid hsl(var(--hue) var(--saturation) 80% / 0.3); | |
border-radius: var(--border-radius); | |
pointer-events: none; | |
} | |
.glow-button:active { | |
scale: 1; | |
} | |
.spark:before { | |
content: ""; | |
position: absolute; | |
} | |
/* Purely to decorate the use of CQ elements sliding along */ | |
.spark:after { | |
/* background: red;*/ | |
content: ""; | |
position: absolute; | |
inset: 0; | |
z-index: -1; | |
} | |
/* Optional backdrop – For some reason, if you go with the mask-composite, you lose the glow... */ | |
.backdrop { | |
position: absolute; | |
inset: 0; | |
background: linear-gradient(transparent 5%, hsl(0 0% 0% / 0.5), transparent) padding-box, | |
radial-gradient(40% 50% at center 100%, hsl(var(--hue) var(--saturation) 72% / 0.15), transparent) padding-box, | |
radial-gradient(80% 100% at center 120%, hsl(var(--hue) var(--saturation) 70% / 0.2), transparent) padding-box, | |
linear-gradient(hsl(var(--hue) var(--saturation) 5%), hsl(var(--hue) var(--saturation) 4%)) padding-box; | |
border: var(--border-width) solid transparent; | |
border-radius: var(--border-radius); | |
transition: background var(--transition) opacity var(--transition); | |
/* opacity: 0;*/ | |
} | |
.glow-button:is(:hover, :focus-visible) { | |
--active: 1; | |
outline: none; | |
} | |
.text { | |
translate: 0 0; | |
letter-spacing: 0.01ch; | |
background: linear-gradient( | |
95deg, | |
hsl(0 0% 90%) 15%, | |
hsl(0 0% 50% / 1), | |
hsl(0 0% 100% / 0.2), | |
hsl(0 0% 80%), | |
hsl(0 0% 90%) 85% | |
); | |
background-size: 500% 100%; | |
background-position: 0 0; | |
-webkit-background-clip: text; | |
background-clip: text; | |
color: transparent; | |
transition: background-position calc(var(--transition) * 6); | |
} | |
.glow-button:is(:hover, :focus-visible) .text { | |
animation: shimmer 1s both; | |
} | |
@keyframes shimmer { | |
0% { | |
background-position: 100% 0; | |
} | |
} | |
.glow-button .spark__container { | |
position: absolute; | |
inset: 0px; | |
/* With a backdrop */ | |
overflow: hidden; | |
/* Without a backdrop */ | |
/*mask: linear-gradient(transparent, transparent), linear-gradient(white, white); | |
mask-clip: padding-box, border-box; | |
mask-composite: intersect; | |
border: var(--border-width) solid transparent;*/ | |
} | |
.glows { | |
filter: blur(calc(var(--blur) * 1px)); | |
container-type: size; | |
position: absolute; | |
inset: 0; | |
} | |
.glow-button > .spark__container { | |
container-type: size; | |
} | |
.glow-button .spark:nth-of-type(2) { | |
rotate: 180deg; | |
animation-direction: alternate-reverse; | |
} | |
.glow-button .spark { | |
position: absolute; | |
left: 0; | |
top: 0; | |
height: 100%; | |
aspect-ratio: 1; | |
border-radius: 0; | |
overflow: visible; | |
mask: none; | |
animation: slide calc(var(--speed) * 1s) ease-in-out infinite alternate; | |
animation-play-state: paused; | |
} | |
.glow-button:hover .spark { | |
animation-play-state: running; | |
} | |
.glow-button .spark:before { | |
inset: -100%; | |
background: conic-gradient( | |
from calc(270deg - (var(--glow-spread) * 0.5)), | |
var(--glow) 0, | |
var(--glow) var(--glow-spread), | |
transparent var(--glow-spread) | |
); | |
translate: 0 0; | |
transform: rotate(0deg); | |
width: auto; | |
animation: spin calc(var(--speed) * 2s) infinite linear; | |
animation-play-state: paused; | |
} | |
.glow-button:is(:hover, :focus-visible) .spark:before { | |
animation-play-state: running; | |
} | |
@keyframes spin { | |
0% { | |
rotate: 0deg; | |
} | |
15%, | |
35% { | |
rotate: 90deg; | |
} | |
65%, | |
85% { | |
rotate: 270deg; | |
} | |
100% { | |
rotate: 360deg; | |
} | |
} | |
@keyframes slide { | |
to { | |
translate: calc(100cqw - 100%) 0; | |
} | |
} | |
/* Overrides */ | |
.glow-button .spark { | |
background: transparent; | |
} | |
.glow-button .spark__container { | |
border-radius: var(--border-radius); | |
opacity: 0; | |
} | |
.spark { | |
transition: opacity var(--transition); | |
opacity: 0; | |
} | |
.glow-button:is(:hover, :focus-visible) .spark { | |
opacity: 1; | |
} | |
.glow-button:is(:hover, :focus-visible) .spark__container:not(.spark__container--reveal) { | |
animation: reveal calc(var(--window) * 1s) both; | |
} | |
@keyframes reveal { | |
0%, | |
100% { | |
opacity: 0; | |
} | |
20%, | |
80% { | |
opacity: 1; | |
} | |
} | |
[data-show-glows="true"] .spark, | |
[data-show-glows="true"] .spark__container:not(.spark__container--reveal) { | |
opacity: 1; | |
} | |
[data-show-glows="true"] .glow-button .spark::before, | |
[data-show-glows="true"] .glow-button .spark { | |
animation-play-state: running; | |
} | |
[data-show-glows="true"] .glow-button:is(:hover, :focus-visible) .spark__container { | |
animation: none; | |
} | |
.label { | |
position: absolute; | |
left: calc(100% + 6rem); | |
translate: 0 -50%; | |
top: 50%; | |
color: hsl(0 0% 80%); | |
opacity: 0; | |
} | |
.spark__container--reveal .spark::after { | |
/* background: red;*/ | |
opacity: 0.65; | |
border: 4px dashed hsl(0 0% 80%); | |
} | |
.labels { | |
position: absolute; | |
inset: 0; | |
} | |
.label--glow { | |
transform: translate3d(0, 0, 100px); | |
} | |
.label--text { | |
transform: translate3d(0, 0, 200px); | |
} | |
.measurements { | |
position: absolute; | |
inset: 0; | |
color: hsl(0 0% 50%); | |
opacity: 0; | |
pointer-events: none; | |
} | |
.width { | |
position: absolute; | |
left: 50%; | |
top: 100%; | |
translate: -50% 100%; | |
} | |
.height { | |
position: absolute; | |
right: 100%; | |
top: 50%; | |
translate: 0% -50%; | |
rotate: 90deg; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment