---
name: radial-glow-background
description: Use when you want "Premium, modern, cinematic" - Uses large blurred radial lights to create atmosphere.
---

# Radial Glow Background

> **Category:** Background  -  **Personality:** Premium, modern, cinematic
>
> **Best use:** AI, SaaS, dark interfaces
>
> **Ratings:** Professional 5/5 - Casual 3/5 - Exotic 4/5 - Visual impact 4/5 - Difficulty 2/5 - Performance cost 2/5

## What it is

A dark hero lit by a few large, very soft pools of coloured light — like distant nebulae or stage lighting bleeding through a black scrim. Each pool is a `radial-gradient` that fades to transparent, composited with `mix-blend-mode: screen` so overlaps **add** light instead of stacking flatly. The pools breathe (slow scale + opacity drift) and one extra glow eases toward the pointer, giving a calm, premium atmosphere. It is the default backdrop for AI/SaaS landing pages because it reads expensive while staying out of the content's way.

It is deliberately different from its neighbours: **Spotlight-Background** is one focused beam/cone aimed at a subject; **Grid-Glow** lights up grid lines. Radial Glow is ambient, edgeless *pools* of colour.

## Dependencies / CDN

**None — pure CSS for the effect, ~15 lines of vanilla JS for the optional cursor glow.** The demo loads display/body fonts (optional):

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Sora:wght@600;700;800&family=Hanken+Grotesk:wght@400;500;600&family=JetBrains+Mono:wght@500&display=swap" rel="stylesheet">
```

## HTML

A dark stage, a field of glow pools (plus the optional cursor glow), then your content on top:

```html
<div class="stage" id="stage">
  <div class="field" aria-hidden="true">
    <span class="glow a"></span>
    <span class="glow b"></span>
    <span class="glow c"></span>
    <span class="glow cursor" id="cursor"></span>
  </div>
  <div class="content">
    <h1>Intelligence that <span class="shine">surrounds</span> every decision.</h1>
    <p>One ambient layer for your docs, code, and conversations.</p>
    <button>Request early access</button>
  </div>
</div>
```

## CSS

```css
/* 1) Dark stage — clip the glows and isolate the blend so screen mixes only here */
.stage{
  position:relative; overflow:hidden; border-radius:26px; isolation:isolate;
  min-height:620px; padding:60px clamp(20px,4vw,40px);
  background:radial-gradient(135% 120% at 50% -10%, #100b22, #08060f 55%, #050410);
}

/* 2) The light pools — a soft radial gradient that fades to transparent.
      screen = additive light: overlaps brighten instead of muddying. */
.field{position:absolute; inset:0; z-index:0; pointer-events:none}
.glow{position:absolute; border-radius:50%; filter:blur(48px); mix-blend-mode:screen;
  will-change:transform,opacity}
.a{width:64%; height:62%; top:-12%; left:-8%;
  background:radial-gradient(circle,rgba(109,77,255,.72),rgba(109,77,255,.3) 38%,transparent 70%);
  animation:breathe 19s ease-in-out infinite}
.b{width:54%; height:58%; top:4%; right:-14%;
  background:radial-gradient(circle,rgba(56,201,255,.58),rgba(56,201,255,.22) 40%,transparent 72%);
  animation:drift 24s ease-in-out infinite}
.c{width:60%; height:62%; bottom:-18%; left:18%;
  background:radial-gradient(circle,rgba(214,72,239,.52),rgba(214,72,239,.2) 42%,transparent 72%);
  animation:breathe 28s ease-in-out infinite reverse}

/* 3) Optional glow that follows the pointer */
.cursor{position:absolute; top:0; left:0; width:540px; height:540px; border-radius:50%;
  filter:blur(54px); mix-blend-mode:screen; pointer-events:none; opacity:.5;
  transition:opacity .6s ease; will-change:transform;
  background:radial-gradient(circle,rgba(176,156,255,.5),rgba(150,132,255,.16) 42%,transparent 70%)}

@keyframes breathe{0%,100%{transform:translate3d(0,0,0) scale(1);    opacity:.5}
                   50%   {transform:translate3d(0,-24px,0) scale(1.14);opacity:.85}}
@keyframes drift  {0%,100%{transform:translate3d(0,0,0) scale(1.05);  opacity:.48}
                   50%   {transform:translate3d(-30px,16px,0) scale(1.18);opacity:.8}}

.content{position:relative; z-index:2; color:#eaecff}

/* Static glows when motion is reduced */
@media (prefers-reduced-motion: reduce){
  .a,.b,.c{animation:none; opacity:.66}
  .cursor{display:none}
}
```

Two cinematic extras used in the demo (optional but cheap): a **vignette** `radial-gradient(125% 115% at 50% 26%, transparent 50%, rgba(3,2,8,.62))` and a faint **film grain** via an inline `feTurbulence` SVG at `opacity:.045; mix-blend-mode:overlay`.

## JavaScript

Optional — only for the pointer-following glow. The ambient pools animate in pure CSS.

```js
(function(){
  var stage=document.getElementById('stage'), glow=document.getElementById('cursor');
  if(!stage||!glow) return;
  if(matchMedia('(prefers-reduced-motion: reduce)').matches) return;   // CSS hides it
  var tx,ty,cx,cy,raf=null;
  function home(){var r=stage.getBoundingClientRect();return{x:r.width*0.5,y:r.height*0.4};}
  var h=home(); tx=cx=h.x; ty=cy=h.y;
  function render(){glow.style.transform='translate3d('+cx+'px,'+cy+'px,0) translate(-50%,-50%)';}
  function loop(){cx+=(tx-cx)*0.09; cy+=(ty-cy)*0.09; render(); raf=requestAnimationFrame(loop);}
  render();
  stage.addEventListener('pointermove',function(e){
    var r=stage.getBoundingClientRect(); tx=e.clientX-r.left; ty=e.clientY-r.top;
    glow.style.opacity='0.85'; if(!raf) loop();           // start the rAF lazily
  });
  stage.addEventListener('pointerleave',function(){var p=home(); tx=p.x; ty=p.y; glow.style.opacity='0.5';});
})();
```

## How it works

- **`radial-gradient(circle, colour, …, transparent)`** is the pool. Because it ends in `transparent`, the edge is inherently soft — no hard circle. The mid stop (e.g. `…,.3) 38%`) controls how quickly it falls off.
- **`mix-blend-mode: screen`** makes the glow *add* its light to the dark stage and to other glows, so two pools overlapping go brighter and shift hue — the core of the "atmosphere" look. `isolation:isolate` on the stage keeps that blending contained to the stage instead of bleeding onto the page.
- **`filter: blur()`** smooths any banding in the gradient and softens the falloff further, selling the "out-of-focus light" feel.
- **Breathing** = animating only `transform` (scale/translate) and `opacity` — both GPU-cheap — so three large blurred layers stay smooth.
- **The cursor glow** is the same recipe; JS just lerps its position toward the pointer (`+= (target-current)*0.09`) each frame for a soft, laggy follow rather than a snappy one.

## Customization

- **Mood / palette:** swap the three gradient colours. Cool indigo + cyan + magenta = "AI nebula" (shown); amber + rose = warm sunrise; a single colour at 3 sizes = restrained and corporate.
- **Density:** 2 pools = minimal, 4–5 = lush. Keep them mostly off-frame (negative `top/left`) so only the soft edge enters the stage.
- **Softness:** raise `blur()` and lower the centre alpha for a hazier, more distant glow; tighten the mid stop for a punchier core.
- **Energy:** shorten the animation durations or increase the `scale`/`translate` deltas for livelier motion; lengthen them for "barely moving" calm.
- **Pure-CSS pointer glow:** drop the JS and drive `.cursor` from a CSS variable updated inline, or just delete it — the ambient pools stand on their own.

## Accessibility & performance

- **Respect `prefers-reduced-motion`:** stop the keyframes (`animation:none`), leave the pools as static light, and skip the JS loop (the demo hides the cursor glow entirely).
- **Animate transform/opacity only — never `filter` or `background`.** Animating the blur radius or gradient stops forces per-frame repaints and will stutter.
- **Keep blurred layers few and large.** A handful of big `blur()` pools is fine; dozens will tax the GPU. `will-change:transform,opacity` hints the compositor.
- **Contrast:** glows are decorative (`aria-hidden="true"`). Ensure body text still clears WCAG over the *brightest* point a pool reaches — the vignette helps by darkening the edges where text often sits.

## Gotchas

- **`mix-blend-mode: screen` needs something dark behind it.** On a light or white stage, screen does almost nothing (white screened with anything stays white). This effect is inherently dark-theme.
- **Forgetting `isolation: isolate`** lets the screen blend reach through to whatever is behind the stage, washing out the page. Isolate (or any new stacking context) confines it.
- **No `overflow: hidden`** and the giant off-frame pools spill out, creating horizontal scroll. Never size pools with `vw`/`vh` against the viewport — size them in `%` of the (clipped) stage.
- **Banding** can appear in large gradients on 8-bit displays; the `blur()` and a touch of grain hide it. Without blur you may see concentric rings.
- **Content legibility drifts as glows move** — position the brightest pools toward the edges/top, not dead-centre behind paragraphs, and lean on the vignette.
