EmpireUI
Get Pro
← Blog7 min read#aurora#gradient#css

Aurora Gradient CSS: Three Ways to Build the Effect From Scratch

Learn three distinct CSS techniques to build aurora gradient effects from scratch — animated conic gradients, blur-layered radials, and GPU-accelerated keyframes.

Colorful aurora borealis gradient light effect on dark background

What the Aurora Effect Actually Is (and Why CSS Can Do It)

Aurora gradients aren't just "colorful blobs." The real northern lights effect is about soft, shifting bands of translucent color — teal bleeding into violet bleeding into a warm amber edge — all sitting on a near-black background. That specific combination of softness, depth, and motion is what makes it feel alive instead of flat.

CSS has been capable of pulling this off since around 2020, when conic-gradient landed in all major browsers. Before that you were hacking it with SVG filters or WebGL. Now you've got three solid pure-CSS paths: animated conic gradients, stacked radial gradient layers with blur(), and keyframe-driven hue rotation. Each has a different trade-off between visual fidelity and performance.

If you want pre-built components that already handle the edge cases, Empire UI's aurora style guide is worth a look before you build from scratch. That said, understanding the CSS mechanics makes you a better consumer of any design system. So let's get into it.

Method 1 — Animated Conic Gradient

Conic gradients sweep color stops around a center point. Combine that with a CSS custom property driving hue-rotate inside a @keyframes block and you get a continuously shifting aurora with maybe 12 lines of CSS.

The key insight: you're not animating the gradient definition itself — you're rotating the hue of the entire element. That keeps the browser happy because hue rotation is cheap. You're not triggering layout or paint on every frame.

.aurora-conic {
  width: 600px;
  height: 400px;
  border-radius: 50%;
  background: conic-gradient(
    from 180deg at 50% 50%,
    #06b6d4 0deg,
    #8b5cf6 120deg,
    #10b981 240deg,
    #06b6d4 360deg
  );
  filter: blur(80px);
  animation: aurora-spin 8s linear infinite;
}

@keyframes aurora-spin {
  from { transform: rotate(0deg) scale(1.2); }
  to   { transform: rotate(360deg) scale(1.2); }
}

Worth noting: the scale(1.2) prevents the blurred edges from revealing the element boundary. At 80px of blur, that boundary shows up as a hard circle around 600px — scale it past 1 and you hide it behind the viewport or parent overflow.

In practice, conic-gradient is the fastest to write and the simplest to tweak. If a client wants "more teal" you're changing one color stop, not refactoring a whole layer stack.

Method 2 — Stacked Radial Gradients With filter: blur()

This one looks the best. It's how most high-end hero sections pull off the aurora feel — multiple radial gradient orbs, each a different color and size, layered on top of each other with mix-blend-mode: screen or lighten. The blur knocks out the hard edges.

The trade-off is DOM complexity. You need separate elements for each orb if you want independent motion. One shared element with multiple background layers can't be animated independently per-layer without a Houdini paint worklet.

// AuroraBackground.jsx
export function AuroraBackground() {
  return (
    <div className="aurora-wrap">
      <div className="orb orb-1" />
      <div className="orb orb-2" />
      <div className="orb orb-3" />
    </div>
  );
}
```
```css
.aurora-wrap {
  position: relative;
  width: 100%;
  height: 100vh;
  background: #0a0a14;
  overflow: hidden;
}
.orb {
  position: absolute;
  border-radius: 50%;
  filter: blur(120px);
  opacity: 0.7;
  mix-blend-mode: screen;
  animation: float linear infinite;
}
.orb-1 {
  width: 700px; height: 700px;
  background: radial-gradient(circle, #06b6d4 0%, transparent 70%);
  top: -200px; left: -100px;
  animation-duration: 14s;
}
.orb-2 {
  width: 500px; height: 500px;
  background: radial-gradient(circle, #7c3aed 0%, transparent 70%);
  top: 20%; right: -150px;
  animation-duration: 18s;
  animation-delay: -6s;
}
.orb-3 {
  width: 400px; height: 400px;
  background: radial-gradient(circle, #10b981 0%, transparent 70%);
  bottom: -100px; left: 30%;
  animation-duration: 22s;
  animation-delay: -11s;
}
@keyframes float {
  0%   { transform: translate(0, 0) scale(1); }
  33%  { transform: translate(40px, -30px) scale(1.05); }
  66%  { transform: translate(-20px, 20px) scale(0.97); }
  100% { transform: translate(0, 0) scale(1); }
}

Honestly, the mix-blend-mode: screen is the secret ingredient here. Without it, your orbs just stack opaquely and you lose the light-bleeding quality that makes auroras look like light and not paint. Screen mode adds the RGB channels, so overlapping regions get brighter — exactly like real light mixing.

Quick aside: if you're shipping this in a Next.js app, wrap the whole thing in will-change: transform on each orb. You'll promote them to their own compositor layers and avoid repainting the rest of the page on every animation frame. That's 120px of blur × 3 elements — your GPU will thank you.

Method 3 — Hue-Rotating a Static Gradient With @keyframes

This is the lowest-overhead option. One element, one gradient, one filter: hue-rotate() animation. You define the gradient once with the color relationships you want, then let the browser cycle the hue over time. The gradient shape stays static; only the perceived color shifts.

.aurora-hue {
  width: 100%;
  height: 100vh;
  background: linear-gradient(
    135deg,
    #0d1b2a 0%,
    #1e3a5f 25%,
    #0d4f3c 50%,
    #2d1b5e 75%,
    #0a0a14 100%
  );
  animation: hue-cycle 12s ease-in-out infinite alternate;
}
@keyframes hue-cycle {
  from { filter: hue-rotate(0deg); }
  to   { filter: hue-rotate(60deg); }
}

Keeping the rotation range tight — 0deg to 60deg — means the colors shift visibly but stay within a cool, space-like palette. Push it to 180deg and you'll get neon greens and reds that break the aurora illusion. Real aurora colors live in that blue-to-green-to-violet band.

This approach works especially well as a subtle page background. It's not competing for attention. The motion reads as ambient rather than animated. If you're building hero sections or dashboard shells where you don't want the background to upstage the UI, this is the one to reach for.

Picking the Right Approach for Your Project

So which method should you actually use? It depends on where the effect lives and how much motion you want. For a full-viewport hero background, Method 2 (stacked orbs) gives you the richest visual result. For a card or widget accent, Method 1 (conic rotation) is fast to write and easy to confine. For ambient site-wide backgrounds, Method 3 is the lightest touch.

Performance-wise: Method 3 wins. One element, one filter, no layout changes. Method 1 is close behind — transform and filter both run on the compositor. Method 2 has the most moving parts and can hit 60fps fine on desktop, but test on mid-range Android before committing. Three blurred elements animating simultaneously will stress a Mali GPU.

If you're already using Empire UI, you'll find aurora-themed components with sensible defaults in the aurora style guide. They handle the prefers-reduced-motion fallback, which you should always include — a full stop on all three animations if the user has that preference set. Don't skip that.

Color Palettes That Actually Work

Aurora color in nature runs from about #00ff87 (green) through #00cfff (teal) into #b66dff (violet) with hints of #ff6b9d (pink) near the horizon. That's your starting point. Don't reach for saturated primary colors — real aurora is de-saturated and slightly washed out, like it's glowing through atmosphere.

Three palettes that reliably work across all three methods: (1) Teal/Violet — #06b6d4#7c3aed; (2) Green/Blue — #10b981#3b82f6; (3) Pink/Purple — #ec4899#8b5cf6. You can mix them but stay within two adjacent palette families. Three-palette mixes tend to look like a pride flag rather than a sky.

Look, the background color matters as much as the gradient. All three methods only work against near-black. On white or light grey, the blurred orbs just turn muddy. Your base should be somewhere between #08080f and #0f172a. The gradient generator tool lets you preview these combos quickly before committing to code.

Accessibility and the prefers-reduced-motion Check

Any time you're running a continuous CSS animation, you need the reduced-motion media query. That's not optional — vestibular disorders make continuously moving backgrounds physically uncomfortable for some users. Two lines of CSS covers it.

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

For the stacked orb method, animation: none leaves you with the static gradient orbs — which still looks good, just not animated. That's a graceful fallback. One more thing — don't set animation: none on the parent wrapper expecting it to cascade. CSS animations don't inherit, so you need to target the animated elements directly.

If you're building with React and want this handled programmatically, the window.matchMedia('(prefers-reduced-motion: reduce)').matches check in a useEffect gives you a boolean you can pipe into a CSS custom property or a conditional class.

FAQ

Does the aurora gradient effect work in Safari?

Yes, as of Safari 15.4 (2022) all three methods — conic-gradient, radial layering, and hue-rotate — have full support. mix-blend-mode: screen has worked in Safari since version 8.

Why does my blurred gradient show a hard circular edge?

The blur radius is exceeding the element boundary. Scale the element up past 1.0 with transform: scale(1.2) or clip it inside a parent with overflow: hidden. The scale fix is usually cleaner.

How do I add the aurora effect to a specific card component without it bleeding outside?

Set position: relative; overflow: hidden on the card, then use position: absolute on the orb elements inside it. The overflow clip keeps everything contained.

What's the performance difference between CSS aurora and a canvas/WebGL version?

For static or slow-moving aurora, CSS is actually faster because the browser compositor handles it without touching the main thread. WebGL only wins if you need procedural noise, physics, or more than ~6 animated layers simultaneously.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

Holographic Effect in CSS: Rainbow Foil Cards and BadgesAurora Gradient Text in CSS: Animated Color-Shift HeadingsText Scramble Effect in CSS + JS: Glitch Characters on HoverCSS Loading Spinners: 12 Variants From Dots to Rings to Bars