Light Rays
A CSS pseudo-element in continuous rotation casts light rays via conic-gradient — an atmospheric animated background, zero JavaScript.
You'll get access to the interactive demo with a free account.
This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Backgrounds has 50 effects, including 6 free. Explore the category →
3 usage examples



How it works
The effect relies on a ::before pseudo-element whose surface is 200% × 200% of the container, centered by combining top: -50%, left: 50%, and transform: translateX(-50%). The .bg-rays container applies overflow: hidden to clip the pseudo-element to its own bounds — whatever angle the ray is at, nothing bleeds outside.
The pseudo-element's background is a conic-gradient with a single luminous segment: transparent → rgba(99, 102, 241, .1) → transparent 30deg. The remaining 330° are fully transparent, giving the impression of a single light ray rather than a color wheel. The semi-transparent indigo (opacity 0.10) blends with the dark background to produce a diffuse, non-aggressive glow.
@keyframes rayRotate animates the pseudo-element from translateX(-50%) rotate(0deg) to translateX(-50%) rotate(360deg) over 20 s, looping infinitely. The translation must appear in both keyframes — if omitted at 0% or 100%, the browser would interpolate it toward zero mid-animation and the pseudo-element would shift off-center. transform-origin: center center ensures rotation around the geometric center of the pseudo-element, which coincides with the center of the container.
Accessibility
- prefers-reduced-motion not present in the code: the animation runs regardless of the system preference. For production use, add
@media (prefers-reduced-motion: reduce) { .bg-rays::before { animation: none; } }. - The
.bg-rayscontainer carries neitheraria-hiddennorrolein the base code. If purely decorative (the usual case), addaria-hidden="true"to exclude it from the accessibility tree. - No keyboard or pointer interaction — the effect is strictly visual and captures no events.
- The gradient is semi-transparent (0.10 opacity at peak): it does not obscure the background or overlay text. Still, verify the WCAG AA contrast ratio with your actual background color / text color combination.
Browser compatibility
conic-gradient is required — available since Chrome 69, Firefox 83, Safari 12.1, Edge 79. Zero JavaScript dependency.
If <code>conic-gradient</code> is not supported, the pseudo-element renders with a transparent background — the container shows its plain background color (<code>#0a0a0f</code>), with no JS errors and no broken layout.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="bg-rays">
<!-- The ::before pseudo-element (CSS) animates the light ray -->
<!-- Overlay content: placed directly as children, already above ::before -->
<div class="your-overlay-content">
<h2>Your headline</h2>
<p>Your subtitle or CTA</p>
</div>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| Ray color (conic-gradient) | rgba(99, 102, 241, .1) | Replace this value in .bg-rays::before to match your brand colors. Any rgba color works — keep opacity between 0.05 and 0.20 to stay legible. |
| Ray opacity (4th rgba param) | .1 | Raise to .18 for a more prominent ray, lower to .05 for a very subtle page backdrop. |
| Rotation speed (animation-duration) | 20s | Replace 20s in the animation: shorthand of .bg-rays::before. 10 s feels dynamic; 40 s is nearly imperceptible movement. |
| Ray width (30deg in conic-gradient) | 30deg | Increase this angular stop (e.g. 60deg) for a wider, more diffuse ray; reduce to 15deg for a sharp beam of light. |
| Background color (.bg-rays background) | #0a0a0f | Change the background property on .bg-rays to adapt the effect to a less dark background — try #0d1117 or #0f172a. |
| Rotation direction (animation-direction) | normal (clockwise) | Add animation-direction: reverse to .bg-rays::before for counter-clockwise rotation — use alternate for a back-and-forth sweep. |
FAQ
@keyframes animation on a ::before pseudo-element, no JS file needed. It works under a strict CSP, inside an HTML email, or in a sandboxed iframe without allow-scripts..bg-rays class: every element carrying that class automatically gets the animation. For different colors or speeds per section, override .bg-rays::before under a parent selector or id — e.g. #hero-section .bg-rays::before { background: conic-gradient(transparent, rgba(99,102,241,.14), transparent 30deg); animation-duration: 15s; }..bg-rays container is already position: relative. Place your child elements directly inside: without special positioning they render above the ::before pseudo-element. For an overlay with a scrim, add a ::after (or a <div>) as position: absolute; inset: 0; background: linear-gradient(…); then place your text in position: relative; z-index: 1.