CHOOSE YOUR GENRE
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.
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
MY STACK
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 theanimationdeclarations 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#0a0a0fbackground 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 minimumrole="button"+tabindex="0"+ akeydownhandler. - No ARIA attributes in the base HTML: no
role="img", noaria-labelon 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.
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.
<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>
.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;
}
}
// Effet CSS pur — pas de JavaScript nécessaire
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| 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.