GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

9 CSS Glow Effect Animations — Neon, Copy-Paste

A glowing button or headline looks lit from the inside like a neon sign, the trick gaming sites, streamers, and portfolios use to catch the eye.

Auto-plays · click a tile to jump to its section · all nine in one zip

The order below follows where a glow shows up on a real page, not popularity. 01 and 02 light up something someone is reading or about to click — a headline, then a button. 03 and 04 sit on cards, one signaling a live state and one following a cursor. 05 and 06 mark a spot — a notification icon, then which tab is active. 07 and 08 solve two problems that plain CSS colors can't: a smooth rainbow cycle and a glow that adapts to light or dark on its own. 09 closes with a glow that reacts to how far a card has scrolled into view. To use the same light as a warning rather than a welcome, the shake animations fit that slot better, and splitting the glow across tiles is what the bento grid hover animations demonstrate.

01Neon text flicker

What it looks like

The letters look lit from the inside, brightening and dimming unevenly instead of holding one steady glow, the way a loosely wired neon tube actually behaves.

Neon text flicker
Open in a new tab

01 · Neon text flicker — Measured area 6.513% · moving frames 14/23Original by GODRICH · SCSS and React ship in the zip · See the password

text-shadow@keyframes flicker다중 그림자

Why it is done this way

Five layers of text-shadow stack up behind the color, and a flicker keyframe with thirteen uneven stops fades the whole stack's opacity in and out so the dips never fall into a predictable beat.

.neon {
  text-shadow:
    0 0 4px #ff2e63,
    0 0 8px #ff2e63,
    0 0 16px rgba(255, 46, 99, .8),
    0 0 32px rgba(255, 46, 99, .6),
    0 0 48px rgba(255, 46, 99, .35);
  animation: flicker 2s linear infinite;
}
@keyframes flicker {
  0%   { opacity: 1; }
  6%   { opacity: .3; }
  14%  { opacity: 1; }
  20%  { opacity: 1; }
  26%  { opacity: .4; }
  34%  { opacity: 1; }
  50%  { opacity: 1; }
  56%  { opacity: .25; }
  64%  { opacity: 1; }
  80%  { opacity: 1; }
  86%  { opacity: .35; }
  94%  { opacity: 1; }
  100% { opacity: 1; }
}

02Button glow on hover

Where a css glow effect button fits

A button carries a faint halo at rest, then the light spreads wider and brighter the instant a cursor hovers over it or keyboard focus lands on it.

Button glow on hover
Open in a new tab

02 · Button glow on hover — Measured area 4.303% · moving frames 11/23Original by GODRICH · SCSS and React ship in the zip · See the password

box-shadow:hover · :focus-visible@keyframes

Worth noting

Two stacked box-shadow layers grow in blur and opacity on :hover and :focus-visible together, so a mouse click and a Tab key press trigger the exact same light.

.btn {
  box-shadow: 0 0 8px rgba(0, 229, 255, .3),
              0 0 16px rgba(0, 229, 255, .12);
  transition: box-shadow .3s ease-out, transform .3s ease-out;
}
.btn:hover,
.btn:focus-visible {
  box-shadow: 0 0 12px #00e5ff,
              0 0 32px rgba(0, 229, 255, .65),
              0 0 48px rgba(0, 229, 255, .3);
  transform: scale(1.06);
}

03Border glow pulse

What you see

A ring of light traced around a card's border breathes wider and dimmer every couple of seconds, like a heartbeat telling a viewer this card is live right now rather than sitting idle.

Border glow pulse
Open in a new tab

03 · Border glow pulse — Measured area 10.727% · moving frames 12/23Original by GODRICH · SCSS and React ship in the zip · See the password

box-shadow 펄스border-color@keyframes

The key property

One box-shadow keyframe swings the blur radius and opacity between a quiet resting state and a bright peak, and the border's position never shifts while it does.

.card { animation: pulse 2s ease-in-out infinite; }

@keyframes pulse {
  0%, 100% {
    box-shadow: 0 0 0 rgba(57, 255, 136, 0), 0 0 8px rgba(57, 255, 136, .18);
    border-color: rgba(57, 255, 136, .35);
  }
  50% {
    box-shadow: 0 0 4px rgba(57, 255, 136, .7),
                0 0 32px rgba(57, 255, 136, .55),
                0 0 48px rgba(57, 255, 136, .22);
    border-color: rgba(57, 255, 136, .9);
  }
}

04Card spotlight glow

Where it fits

A patch of colored light drifts in a slow loop across a card until a cursor lands on it, at which point the light stops looping and follows the pointer instead.

Card spotlight glow
Open in a new tab

04 · Card spotlight glow — Measured area 20.233% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

@propertyradial-gradient@keyframes sweep

What to read in the code

A radial-gradient reads its center from two custom properties, --x and --y, and those only interpolate smoothly through @keyframes because @property registers them as a <percentage> first — an unregistered custom property would just jump from one value to the next with no motion in between.

@property --x { syntax: '<percentage>'; inherits: false; initial-value: 50%; }
@property --y { syntax: '<percentage>'; inherits: false; initial-value: 50%; }

.card::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(circle at var(--x) var(--y),
              rgba(179, 107, 255, .55), transparent 55%);
  animation: sweep 2s ease-in-out infinite;
}
@keyframes sweep {
  0%   { --x: 18%; --y: 20%; }
  25%  { --x: 85%; --y: 22%; }
  50%  { --x: 78%; --y: 80%; }
  75%  { --x: 20%; --y: 76%; }
  100% { --x: 18%; --y: 20%; }
}

05Icon glow ring

What moves

Two rings expand outward from a small icon and fade to nothing, one starting half a beat after the other, reading like a signal broadcasting outward the way a live or notification dot often does.

Icon glow ring
Open in a new tab

05 · Icon glow ring — Measured area 6.007% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

animation-delaybox-shadow 링scale · opacity

How it is built

Both rings only animate scale and opacity on a staggered animation-delay, which makes this the lightest-weight glow in the whole set.

.ring {
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 2px solid #ffb020;
  opacity: 0;
}
.ring--a { animation: ring 2s ease-out infinite; }
.ring--b { animation: ring 2s ease-out infinite; animation-delay: 1s; }

@keyframes ring {
  0%   { transform: scale(.7); opacity: .8; }
  70%  { transform: scale(1.7); opacity: 0; }
  100% { transform: scale(1.7); opacity: 0; }
}

06Underline glow

The moment it fires

A glowing underline slides beneath whichever tab is active, trailing a soft box-shadow behind it instead of snapping straight into place.

Underline glow
Open in a new tab

06 · Underline glow — Measured area 3.618% · moving frames 7/23Original by GODRICH · SCSS and React ship in the zip · See the password

translateXbox-shadowlinear-gradient

How it works

Both tabs sit at a fixed 96px width, so the underline's travel distance is one fixed number inside a translateX keyframe rather than something measured off the rendered page after the fact.

.tab { flex: 0 0 auto; width: 96px; }

.indicator {
  position: absolute; left: 0; bottom: -8px;
  width: 96px; height: 3px;
  background: linear-gradient(90deg, transparent, #2df5c0, transparent);
  box-shadow: 0 0 12px #2df5c0, 0 0 24px rgba(45, 245, 192, .6);
  animation: slide 2s cubic-bezier(.2, .8, .2, 1) infinite;
}
@keyframes slide {
  0%, 40%  { transform: translateX(0); }
  60%, 90% { transform: translateX(112px); }
  100%     { transform: translateX(0); }
}

07@property glow color cycle

What the user notices

A round badge's glow drifts through the whole color wheel on a two-second loop, never landing on the same shade twice in a cycle.

@property glow color cycle
Open in a new tab

07 · @property glow color cycle — Measured area 4.603% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

@propertyhsl(var(--hue))무한 색상 순환

How to wire it up

That smooth sweep only works because --hue is registered through @property as a <number>, letting hsl() interpolate the hue angle instead of jumping straight from one color to the next.

@property --hue { syntax: '<number>'; inherits: false; initial-value: 262; }

.badge {
  width: 80px; height: 80px;
  border-radius: 50%;
  box-shadow: 0 0 16px #8b5cf6, 0 0 40px rgba(139, 92, 246, .5);
  animation: cycle 2s linear infinite;
}
@supports (background: hsl(var(--hue) 100% 50%)) {
  .badge {
    box-shadow: 0 0 16px hsl(var(--hue) 90% 62%),
                0 0 40px hsl(var(--hue) 90% 55% / .55);
  }
}
@keyframes cycle {
  from { --hue: 0; }
  to   { --hue: 360; }
}

08light-dark() aware glow

Where this shows up

The same kind of badge glows faintly on a light background and strongly on a dark one, with no media query anywhere in the file and no JavaScript checking which theme is active.

light-dark() aware glow
Open in a new tab

08 · light-dark() aware glow — Measured area 4.275% · moving frames 8/23Original by GODRICH · SCSS and React ship in the zip · See the password

light-dark()color-schemebox-shadow

The core of it

Once color-scheme is set on the surrounding element, writing the glow's color through light-dark() lets that one line pick the right shade for itself on either background.

.pane--light { color-scheme: light; }
.pane--dark  { color-scheme: dark; }

.badge {
  --glow-rest: light-dark(rgba(124, 92, 255, 0), rgba(124, 92, 255, .2));
  --glow-peak: light-dark(rgba(124, 92, 255, .7), #7c5cff);
  box-shadow: 0 0 4px var(--glow-rest);
  animation: breathe 2s ease-in-out infinite;
}
@keyframes breathe {
  0%, 15%, 85%, 100% { box-shadow: 0 0 4px var(--glow-rest); }
  35%, 65%            { box-shadow: 0 0 16px var(--glow-peak); }
}

09Glow intensity tied to scroll

What happens on screen

A card's glow builds from barely-there to fully lit as it nears the center of the screen while scrolling, then fades back down once it drifts past.

Glow intensity tied to scroll
Open in a new tab

09 · Glow intensity tied to scroll — Measured area 1.083% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

IntersectionObserver(JS)@propertybox-shadow

The idea behind it

An IntersectionObserver writes the intersection ratio straight into a registered --intensity custom property, and both box-shadow and opacity read that same value through calc(), so the glow and the fade always move together.

@property --intensity { syntax: '<number>'; inherits: false; initial-value: 0; }

.card {
  opacity: calc(.45 + var(--intensity) * .55);
  box-shadow: 0 0 calc(var(--intensity) * 12px) #3ec9ff,
              0 0 calc(var(--intensity) * 40px) rgba(62, 201, 255, .55);
  transition: box-shadow .3s linear, opacity .3s linear;
}

Where does light-dark() break?

What goes wrong

Item 08's badge, the one css neon glow effect here that has to survive both themes, only ever feeds light-dark() a <color> — the resting glow, the peak glow, the panel background. The first build of this demo also tried feeding it a length, swapping the blur radius between a smaller value on light panels and a wider one on dark panels. That version didn't render a dimmer glow on the wrong background — it rendered no glow at all, because light-dark() outside a <color> value doesn't fall back to either side quietly — it makes the entire box-shadow declaration invalid, and an invalid declaration gets dropped by the browser with no console warning.

How to avoid it

The point where overlapping bloom muddies the color shows up first in the AI orb landing kit, which parks one large glowing mass in the middle of the screen.

A 24-frame capture of that broken version measured zero frames of motion before the fix went in: keep light-dark() inside colors only, and leave every length — blur, spread, radius — as a plain number outside it. The full SCSS and React source for all nine glows, including the exact line that broke item 08 before the fix, opens with azk2eev6, typed exactly as it reads here. One more thing worth knowing before copying any of this: box-shadow repaints every frame instead of compositing on the GPU the way transform and opacity do, so stacking more than two or three layers — 01, 03, and 04 already sit at that edge — is the kind of choice that costs frame rate first on a low-end phone.

Variants worth trying

Variant Changed value Feel
Softer spotlight Item 04's gradient stop cut from 55% to 35% The light pools tighter around the cursor instead of washing across the whole card
Urgent flicker Item 01's 2s loop shortened to 800ms Reads like a warning light rather than a lazily buzzing neon tube
Brand-locked cycle Item 07's --hue keyframes limited to 200 through 260 Stays inside blue-violet the whole loop instead of crossing the full rainbow

Accessibility

What reduced motion leaves

All nine drop their animation to none under prefers-reduced-motion: reduce, but the glow itself — the color, the shadow — stays on the page; only the motion goes quiet. 01 settles at a steady full-opacity glow instead of flickering, 03 holds one steady mid-brightness glow instead of pulsing, and 04, 07, and 09 freeze their @property values at a sensible default — the spotlight centers itself, the hue cycle parks on one violet, and the scroll glow reads as fully lit rather than snapping to zero. Browser coverage is the other limit worth knowing: @property reaches Chrome/Edge 85+ and Safari 16.4+, but Firefox only added it in version 128, and light-dark() needs Chrome/Edge 123+, Firefox 120+, or Safari 17.5+.

What else to check

Older engines skip 04, 07, 08, and 09's animated part and fall back to the static glow color already written into the CSS — nothing breaks, it just stops moving. More hover and click effects in the same copy-paste format live in 9 CSS button animations, and the rest of what this site has published sits in the CSS category hub.

FAQ

Do I need a css glow effect generator, or is this short enough to write by hand?

Every rule above is six to twenty lines of plain SCSS, short enough to type or paste without a generator tool. A generator is worth reaching for when you need dozens of one-off variations fast, but it usually outputs more shadow layers and vendor cruft than any of the nine here actually need.

Why does my text-shadow neon effect look flat instead of glowing?

A single text-shadow layer reads as a hard-edged outline, not a glow — glow comes from stacking several layers at increasing blur radius and decreasing opacity, the way item 01 stacks five. Skipping the outer, most-blurred layers is the most common reason a "neon" text effect ends up looking like plain colored text with a shadow.

What's the real difference between text-shadow and box-shadow for a glow?

text-shadow only follows the shape of glyphs, so it's the right choice for glowing letters like item 01. box-shadow follows an element's box (or its border-radius), which is why every glow on a button, card, or badge in this set — 02 through 09 — uses box-shadow instead. When the light has to wrap a whole card and answer the pointer, that combination is worked out in the CSS card hover effects.

Enter the archive password

The password is inside this article. You will find it as you read.