BackgroundsFree

Neon Glow Pulse

Bordered elements pulsing through stacked box-shadow layers — three desynchronised neon variants (pink, cyan, green) on a dark background, pure CSS, no script.

CSSAnimationNeon
Pink
Cyan
Neon
Hover or click the scene to interact

This effect is free — the Backgrounds category contains 50 effects total, including 6 free. Effect.Labs has 811 vanilla effects. Explore the category →

Usage examples

CHOOSE YOUR GENRE

Explore the universe

Action
RPG
Survival

① Gaming site — Neon category tags in the hero

WhenA gaming site's homepage, creative platform, or dark-mode app displays its main sections or categories as glowing labels on a black background.
WhyThree desynchronised halos fill a large dark surface naturally without an image — each pulse draws the eye in turn, creating overall movement without feeling frantic.
Settingsanimation-duration: 1.5 s / 2 s / 2.5 s for a livelier rhythm; font-size: 1.1 rem; padding: 14px 28px; text replaced with navigation labels.
KrossLight Gaming
142 K subscribers
● LIVE
48 203 viewers
Stream active

② Streamer live page — LIVE banner and viewer counter

WhenA streamer homepage or gaming broadcast interface shows a pulsing 'LIVE' banner and a real-time viewer count on a dark background.
WhyIn a broadcast context, the pulsing halo is an expected signal — it visually codes 'this is alive, happening now'. The three colours (pink for LIVE, cyan for the viewer count, green for stream status) each carry strong semantic meaning — the neon aesthetic is functional here, not decorative.
Settingsanimation-duration: 1.5 s for the LIVE badge (felt urgency), 2.5 s / 3 s for secondary badges; padding: 9px 18px; font-size: 0.78 rem; border-radius: 6px for a tech look.
Jean Dupont
Full stack developer

MY STACK

TypeScript
Three.js
Rust

③ Dark-mode portfolio — Technical skill tags

WhenA developer or creative agency lists their technologies on a portfolio page with a black or dark background.
WhyNeon tags turn a skill list into a strong visual element — each colour can distinguish a category (frontend, backend, tooling) without icon overload.
SettingsCustom colours: purple #7c3aed, blue #0ea5e9, emerald #10b981; letter-spacing: 0.05 em; border-radius: 6px for a more technical look.

How it works

The effect is built entirely on multi-value box-shadow: each element stacks up to five outer shadows (5 px, 10 px, 20 px, 50 px, 80 px blur) and one inner shadow. Between the 0 %/100 % keyframes (restrained glow: 5 px, 10 px, 20 px + 10 px inset) and 50 % (peak glow: 10 px, 25 px, 50 px, 80 px + 20 px inset), the browser interpolates the blur radii — this continuous interpolation creates the breathing-light effect.

text-shadow applies two layers on the text itself (10 px and 20 px blur) in the same colour as the border and halo. The color, border: 2px solid, text-shadow, and box-shadow values all share the same RGB value — removing any one of them breaks the neon illusion.

Three separate @keyframes (neonPulsePink, neonPulseCyan, neonPulseGreen) run at different durations: 2 s, 2.5 s, 3 s. These periods are deliberately non-integer multiples of each other, ensuring the three elements never pulse in phase — the ensemble feels organic, not mechanical.

No JavaScript, no requestAnimationFrame, no DOM mutation. The animation property is ease-in-out infinite: the browser handles all timing natively in CSS. The dark background (rgb(10,10,15)) is owned by .neon-glow-container — it is constitutive of the effect; without a dark background, contrast drops and the halo vanishes visually.

Accessibility

  • No prefers-reduced-motion support: the code contains no @media (prefers-reduced-motion: reduce) block. The animation pulses continuously regardless of OS preferences. Fix: move the animation declarations inside @media (prefers-reduced-motion: no-preference) { … } and keep the static state (0 %/100 % keyframe values) as the default.
  • WCAG AA contrast: the neon colours — pink #ff2d95, cyan #00f0ff, green #39ff14 — on the #0a0a0f background exceed the 4.5:1 ratio required for normal text. Text content remains readable even if the animation fails.
  • Base elements are plain <div> with no interactive semantics. If the effect wraps buttons or links, use native <button> or <a> — or at minimum role="button" + tabindex="0" + a keydown handler.
  • No ARIA attributes in the base HTML: no role="img", no aria-label on the container. Complete these according to the integration context.
  • Pure CSS effect: no script runs, no focus is captured — screen readers read the text content of the <div> elements directly.

Browser compatibility

Requires multi-value box-shadow and @keyframes CSS — supported in all modern browsers since 2012. Zero external dependencies.

Chrome 88+✓ Full
Firefox 87+✓ Full
Safari 15+✓ Full
Edge 88+✓ Full
Mobile iOS✓ Full
Android Chrome✓ Full

On a browser without <code>@keyframes</code> support (extremely rare), elements display with their static halo (0 %/100 % values — a faint neon glow) — no JS errors, readability is preserved.

The code

Copy the three blocks into your page. No dependencies.

HTML
<div class="chroma-demo neon-glow-container">
  <div class="neon-element neon-pink">Pink</div>
  <div class="neon-element neon-cyan">Cyan</div>
  <div class="neon-element neon-green">Neon</div>
</div>
CSS
.chroma-demo  {
   width: 100%;
   height: 100%;
   display: flex;
   align-items: center;
   justify-content: center;
   min-height: 200px;
   border-radius: 8px;
   overflow: hidden;
   position: relative;
   }

.neon-glow-container  {
   display: flex;
   align-items: center;
   justify-content: center;
   gap: 20px;
   background: rgb(10, 10, 15);
   flex-wrap: wrap;
   padding: 24px;
   }

.neon-element  {
   padding: 12px 24px;
   border-radius: 12px;
   font-weight: 700;
   font-size: 0.85rem;
   text-transform: uppercase;
   letter-spacing: 0.1em;
   position: relative;
   }

.neon-pink  {
   color: rgb(255, 45, 149);
   border: 2px solid rgb(255, 45, 149);
   text-shadow: rgb(255, 45, 149) 0px 0px 10px, rgb(255, 45, 149) 0px 0px 20px;
   animation: 2s ease-in-out 0s infinite normal none running neonPulsePink;
   }

.neon-cyan  {
   color: rgb(0, 240, 255);
   border: 2px solid rgb(0, 240, 255);
   text-shadow: rgb(0, 240, 255) 0px 0px 10px, rgb(0, 240, 255) 0px 0px 20px;
   animation: 2.5s ease-in-out 0s infinite normal none running neonPulseCyan;
   }

.neon-green  {
   color: rgb(57, 255, 20);
   border: 2px solid rgb(57, 255, 20);
   text-shadow: rgb(57, 255, 20) 0px 0px 10px, rgb(57, 255, 20) 0px 0px 20px;
   animation: 3s ease-in-out 0s infinite normal none running neonPulseGreen;
   }

@keyframes neonPulsePink  {
   
  0%, 100%  {
   box-shadow: rgb(255, 45, 149) 0px 0px 5px, rgb(255, 45, 149) 0px 0px 10px, rgb(255, 45, 149) 0px 0px 20px, rgba(255, 45, 149, 0.1) 0px 0px 10px inset;
   }
  50%  {
   box-shadow: rgb(255, 45, 149) 0px 0px 10px, rgb(255, 45, 149) 0px 0px 25px, rgb(255, 45, 149) 0px 0px 50px, rgb(255, 45, 149) 0px 0px 80px, rgba(255, 45, 149, 0.15) 0px 0px 20px inset;
   }
}

@keyframes neonPulseCyan  {
   
  0%, 100%  {
   box-shadow: rgb(0, 240, 255) 0px 0px 5px, rgb(0, 240, 255) 0px 0px 10px, rgb(0, 240, 255) 0px 0px 20px, rgba(0, 240, 255, 0.1) 0px 0px 10px inset;
   }
  50%  {
   box-shadow: rgb(0, 240, 255) 0px 0px 10px, rgb(0, 240, 255) 0px 0px 25px, rgb(0, 240, 255) 0px 0px 50px, rgb(0, 240, 255) 0px 0px 80px, rgba(0, 240, 255, 0.15) 0px 0px 20px inset;
   }
}

@keyframes neonPulseGreen  {
   
  0%, 100%  {
   box-shadow: rgb(57, 255, 20) 0px 0px 5px, rgb(57, 255, 20) 0px 0px 10px, rgb(57, 255, 20) 0px 0px 20px, rgba(57, 255, 20, 0.1) 0px 0px 10px inset;
   }
  50%  {
   box-shadow: rgb(57, 255, 20) 0px 0px 10px, rgb(57, 255, 20) 0px 0px 25px, rgb(57, 255, 20) 0px 0px 50px, rgb(57, 255, 20) 0px 0px 80px, rgba(57, 255, 20, 0.15) 0px 0px 20px inset;
   }
}
JavaScript (fx-0086)
// Effet CSS pur — pas de JavaScript nécessaire

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
color / border-color / text-shadow in .neon-pink, .neon-cyan, .neon-green pink #ff2d95 · cyan #00f0ff · green #39ff14 All three properties must share the same RGB value to maintain halo coherence. Rename the classes if you prefer semantic identifiers (.neon-primary, .neon-alert).
animation-duration in .neon-pink / .neon-cyan / .neon-green 2 s · 2.5 s · 3 s Pulse cycle duration per variant. Keep different values to preserve desynchronisation — exact multiples (e.g. 2 s / 4 s / 6 s) re-sync the elements and break the organic feel.
box-shadow blur 80px at 50% in @keyframes neonPulse* 80 px Blur radius at the peak of the halo. Reduce to 40 px for a contained look (component), increase to 120–140 px for a dramatic burst (full-screen hero).
padding in .neon-element 12px 24px Physical size of the tags. Reduce to 6px 12px for micro-badges, increase to 16px 40px for buttons or section headings.
font-size in .neon-element 0.85 rem Text size. Go up to 1.2–1.6 rem for section headings; the halo scales proportionally without touching the keyframes.
gap in .neon-glow-container 20 px Spacing between elements. At 8 px the halos visually touch and merge into a continuous light band.
border-radius in .neon-element 12 px 0 px = square tags (retro terminal style), 4 px = slightly rounded corner, 50 px = pill — the halo follows the outline exactly.

FAQ

Does the effect work on a light background?

Technically yes, but the neon illusion disappears: box-shadow halos are additive colours that need a dark background to appear luminous. On white or light grey, the same values produce a plain coloured outline with no depth. Place the .neon-glow-container inside a dark section or dark overlay.

How do I add a fourth colour variant?

Create a .neon-purple class mirroring .neon-pink, replacing the RGB value — e.g. rgb(168,85,247) for purple — in color, border, text-shadow, and the box-shadow values inside a new @keyframes neonPulsePurple. Assign a distinct duration (e.g. 3.5 s) to maintain desynchronisation.

Can the glow trigger on hover rather than looping continuously?

Yes — remove the animation declaration from the .neon-* classes and replace it with transition: box-shadow 0.3s ease. On :hover, apply the 50 % keyframe values (peak halo). Result: minimal static glow at rest, full glow on hover, no looping animation — also more respectful of prefers-reduced-motion.