← Back to gallery
CSSFeatured

Aurora Gradient Sweep

Layered radial-gradient blobs drift behind readable foreground content via transform + opacity, no gradient-stop interpolation. Three palettes — cool polar, warm sunset, and an ambient quiet header for low-motion contexts.

auroraradial-gradientbackground-layerblurambient-motionprefers-reduced-motion

Background / Gradient Layers

Aurora Gradient Sweep

Layered radial gradients drift with transform, background-position, and opacity instead of relying on gradient stop interpolation.

Cool layer drift

Polar Band

Soft cyan and violet bands drift behind a legibility-preserving foreground surface. Keep text on an independent surface and let the aurora layer remain decorative.

  • gradient-layers
  • transform
  • opacity

Warm accent pass

Sunset Veil

A warmer aurora pass adds amber and rose without making the foreground copy glow. Warm layers are lower opacity so they do not collapse contrast on dark UI.

  • sweep-blur
  • warm stops
  • contrast

Low-motion background

Quiet Header

A restrained band works for headers that need depth but not constant attention. Use longer durations and smaller travel distances when the effect sits behind navigation.

  • ambient
  • long duration
  • background

Aurora inspector

Polar Band

  • gradient-layers
  • transform
  • opacity

Soft cyan and violet bands drift behind a legibility-preserving foreground surface. Keep text on an independent surface and let the aurora layer remain decorative.

Helped you ship something? 🐟 Send my cat a churu

.aurora {
  position: absolute;
  inset: -30%;
  background:
    radial-gradient(circle at 20% 40%, #22d3ee, transparent 32%),
    radial-gradient(circle at 74% 28%, #a78bfa, transparent 36%);
  filter: blur(calc(22px * 1.00));
  animation: auroraDrift 9.00s ease-in-out infinite alternate;
}

@media (prefers-reduced-motion: reduce) {
  .aurora { animation: none; }
}

How to make this

A CSS aurora gradient uses oversized blurred radial-gradient layers behind the content, then drifts those layers with transform and opacity instead of animating gradient stops.

html
1<div class="aurora-card">  <span class="aurora-card__glow aurora-card__glow--one"></span>  <span class="aurora-card__glow aurora-card__glow--two"></span></div> <style>.aurora-card {  position: relative;9  isolation: isolate;  overflow: hidden;  min-height: 220px;  border-radius: 24px;  background: #08111f;}.aurora-card__glow {  position: absolute;17  inset: -35%;  z-index: -1;  border-radius: 45%;20  filter: blur(28px);  opacity: 0.68;22  mix-blend-mode: screen;  animation: aurora-card-drift 9s ease-in-out infinite alternate;}25.aurora-card__glow--one {  background:    radial-gradient(circle at 25% 38%, #22d3ee, transparent 30%),    radial-gradient(circle at 75% 30%, #a78bfa, transparent 34%);}.aurora-card__glow--two {  background:    radial-gradient(circle at 40% 70%, #34d399, transparent 28%),    radial-gradient(circle at 70% 72%, #22d3ee, transparent 30%);  opacity: 0.42;  animation-name: aurora-card-drift-alt;  animation-duration: 11s;}@keyframes aurora-card-drift {  from { transform: translate3d(-10%, -4%, 0) rotate(-8deg); }  to   { transform: translate3d(12%, -10%, 0) rotate(18deg); }}@keyframes aurora-card-drift-alt {  from { transform: translate3d(9%, 8%, 0) rotate(-12deg); }  to   { transform: translate3d(-12%, 10%, 0) rotate(16deg); }}46@media (prefers-reduced-motion: reduce) {  .aurora-card__glow { animation: none; }}</style>

Annotated snippet

  1. Line 1The card is the clipping container that hosts the aurora layers. Keep it as a positioned, overflow-hidden surface so the blurred glows have a defined frame to drift inside.
  2. Line 9isolation: isolate creates a local stacking context. That keeps mix-blend-mode and negative z-index layers from blending with the whole page behind the component.
    PitfallWhich browsers support mix-blend-mode for this effect?

    Modern Chromium, Firefox, and Safari support mix-blend-mode, but rendering can vary with stacking contexts and backdrop effects. The safe fallback is simple: keep the dark base background and radial-gradient layers, then remove mix-blend-mode. The aurora becomes less luminous, but the layout and content still work.

  3. Line 17The glow is oversized with inset: -35% so the blurred edges start outside the card. Without that runway, the blur clips into hard rectangular edges during the drift.

    Only inset changes here. With inset: 0 the blurred edge is clipped at the card wall; with inset: -35% the same glow has room to fade before it reaches the wall.

    PitfallWhy should a CSS aurora use separate layers instead of one animated gradient?

    Separate absolutely positioned layers are easier to control. You can move them with transform, tune opacity per layer, and keep the foreground content on a stable surface. A single animated background often pushes you toward background-position or gradient-stop tricks that are harder to make readable and harder to pause cleanly.

  4. Line 20filter: blur(28px) is what turns sharp radial gradients into an aurora. Without it the layers read as hard circles; with it they read as soft, additive light.

    Only filter changes here. The same hard-stop color circles stay visibly cut with blur(0), then dissolve into soft aurora light with blur(16px).

  5. Line 22mix-blend-mode: screen lets the color layers add light over the dark base. Keep it on the decorative glow layers so the dark base shines through where the colors meet.

    Only mix-blend-mode changes here. The same two blurred layers overlap as paint normally, then add light when screen is applied.

    PitfallWhich browsers support mix-blend-mode for this effect?

    Modern Chromium, Firefox, and Safari support mix-blend-mode, but rendering can vary with stacking contexts and backdrop effects. The safe fallback is simple: keep the dark base background and radial-gradient layers, then remove mix-blend-mode. The aurora becomes less luminous, but the layout and content still work.

  6. Line 25Two glow layers with different palettes and drift keyframes give the aurora its motion. A single layer drifts as one rigid blob; two layers with different timings produce the wandering shimmer.

    A single layer drifts as one rigid color cloud. Two layers with different palettes and timings cross-fade as they move, producing the wandering aurora shimmer.

    PitfallWhy should a CSS aurora use separate layers instead of one animated gradient?

    Separate absolutely positioned layers are easier to control. You can move them with transform, tune opacity per layer, and keep the foreground content on a stable surface. A single animated background often pushes you toward background-position or gradient-stop tricks that are harder to make readable and harder to pause cleanly.

  7. Line 46Reduced motion freezes the drifting layers but keeps the static color field. The pattern remains visually recognizable without constant background movement.
    PitfallHow should aurora gradients handle prefers-reduced-motion?

    Freeze the layer animations under @media (prefers-reduced-motion: reduce). Do not remove the decorative layers unless they harm contrast, because the static gradient can still provide useful depth. If the aurora sits behind navigation or form controls, consider reducing opacity as well as stopping animation.

Other pitfalls

Is filter: blur expensive for aurora backgrounds?
It can be. Large blurred layers are costly on low-end mobile devices, especially if several cards animate at once. Keep the layer count low, keep the blurred area bounded with overflow: hidden, and animate transform/opacity rather than filter radius. For long pages, run the aurora only in the hero or pause offscreen instances.
Advanced

Cycle hue-rotate through the existing filter chain — real auroras shift color, not just position

Same two oversized blurred radial-gradient layers, same transform drift, same mix-blend-mode: screen, same blur(16px). BEFORE keeps the filter chain frozen at blur only — the palette is whatever the gradients paint at first frame and never shifts. AFTER adds hue-rotate as a second function in the same filter chain and animates it on a 6s cycle synced with the drift; the cyan and purple stops drift through magenta and pink and back. The gradients themselves are never re-painted (the slug's rule); the rasterized layer just has a different color matrix applied each frame.

View explanation and full code24 lines

The base teaches drift via transform (cheap, GPU-composited) and warns against animating gradient stops (expensive per-frame paint). Real auroras drift AND shift hue over time — but animating gradient stops is exactly what the slug rules out. The right extension layers a slow filter: hue-rotate cycle onto the existing filter chain (already running blur). hue-rotate is GPU-composited like blur: it applies a color matrix to the rasterized layer, never re-paints the gradient. Same filter property the base already uses, just one more function in the chain and one more keyframe cycle — drift stays untouched, color shifts independently.

Append these rules inside the <style> block from the base snippet above.

css
/* Advanced: hue-rotate cycle — extends the base recipe.   Adds a slow hue-rotate cycle to the existing filter chain on each   glow. The transform-based drift keeps running on its own animation;   the hue-rotate runs on a longer independent cycle so the cyan/purple   palette slowly shifts toward magenta/pink and back, like a real   aurora drifting through wavelengths. Same filter property the base   already uses (blur stays as-is); no gradient-stop animation. */.aurora-card__glow {  animation:    aurora-card-drift 9s ease-in-out infinite alternate,    aurora-card-hue 14s ease-in-out infinite;}.aurora-card__glow--two {  animation:    aurora-card-drift-alt 11s ease-in-out infinite alternate,    aurora-card-hue 14s -7s ease-in-out infinite;}@keyframes aurora-card-hue {  0%, 100% { filter: blur(28px) hue-rotate(0deg); }  50%      { filter: blur(28px) hue-rotate(70deg); }}@media (prefers-reduced-motion: reduce) {  .aurora-card__glow { animation: none; }}

Notes

Overview

A CSS aurora gradient background drifts layered radial-gradient blobs behind foreground content via transform + opacity — no gradient-stop interpolation, no JS frame loop. The visual reads as ambient depth because two or more colored blobs slide past each other on different cycle lengths, occasionally overlapping for a brighter hot spot. Foreground content stays anchored on a legibility surface so the aurora never compromises reading contrast.

When to use it

Reach for aurora drift on hero sections, marketing surfaces, and dashboard headers that want depth without competing for reading attention. Skip it under any layout where the user needs to focus on dense text or fine UI — the constant motion in peripheral vision is exhausting. Skip it for the body of a documentation page; reserve ambient motion for above the fold or behind a hero card.

How it works

Each aurora layer is an absolutely-positioned <span> at inset: -34% so the radial gradient extends past the parent and never reveals a hard edge. The layer animates a translate3d + rotate + scale keyframe with ease-in-out infinite alternate, so the layer breathes back and forth instead of looping with a visible seam. Two layers on offset cycle durations (e.g. 8.6s and 10.4s) drift independently, which is what makes the brighter overlap moments feel non-repeating.

The important production distinction is that the radial-gradient() itself does not animate. The browser only moves a pre-painted layer with transform, while opacity controls how strongly each aurora color field blends into the surface. That keeps the animated aurora background closer to compositor work than paint work, which is the difference between a calm hero effect and a janky gradient demo.

Production gotchas

filter: blur() on the aurora layer is GPU-cheap but creates a stacking context that traps mix-blend-mode from siblings — the legibility surface on top should sit in a different stacking context or the blend will look wrong. Layers at inset: -34% need an overflow: hidden parent or the gradient bleeds out of the card on subpixel scrolls. On low-end devices the Gaussian blur on multiple layers can drop frames; the pattern runs cleanly because the blobs animate transform-only, but if you add a third layer keep the blur radius under 28px.

Accessibility

Ambient motion is one of the textbook vestibular triggers, so the prefers-reduced-motion: reduce branch freezes the layer transforms at their rest position. Foreground content is the only thing screen readers see; the layers are aria-hidden="true" and pointer-events: none.

References

Implementation depth

The aurora should move layers, not gradient stops. Paint radial-gradient blobs once, then animate transform and opacity so the browser can keep the effect closer to compositor work than repeated gradient repainting.

Depth comes from overlapping cycle lengths. Use two or three layers with slightly different durations, then test foreground contrast at the brightest overlap frame; the calmest-looking rest state is rarely the worst contrast case.