Bokeh Lights

Soft out-of-focus orbs of light drift and pulse behind the content, like city lights seen through a lens.

  • CSS
  • Backgrounds
  • Loop
  • Added

Evening edition

AI prompt

Create a bokeh light background in pure CSS. Place about ten absolutely positioned circles with random sizes (30–110px), positions, and warm hues set through inline CSS custom properties. Give each a radial-gradient fill that fades to transparent, filter: blur(6px), and mix-blend-mode: screen so overlapping orbs brighten. Animate each with a keyframe that drifts translate by ±20px and scales between 0.85 and 1.1 while opacity breathes between 0.35 and 0.8, using alternate infinite timing with a different duration (8–16s) and negative delay per orb so they never move in sync. Pause the animations when off screen. Under prefers-reduced-motion, keep the orbs still. The headline reads "Evening edition".

Source

Demo.tsx
'use client'

import { useEffect, useRef } from 'react'
import s from './demo.module.css'

// Fixed values so server and client render the same markup.
const ORBS = [
  [8, 20, 70, 40, 9], [22, 70, 40, 60, 12], [35, 30, 100, 30, 14], [48, 80, 55, 70, 10], [60, 15, 80, 50, 16],
  [72, 60, 110, 25, 11], [85, 30, 45, 80, 13], [92, 75, 65, 45, 8], [15, 50, 35, 90, 15], [55, 45, 30, 20, 9],
]

export default function Bokeh({ labels }: { labels: Record<string, string> }) {
  const ref = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const el = ref.current
    if (!el) return
    const io = new IntersectionObserver(([e]) => el.toggleAttribute('data-paused', !e.isIntersecting))
    io.observe(el)
    return () => io.disconnect()
  }, [])

  return (
    <div ref={ref} className={s.scene}>
      {ORBS.map(([x, y, size, hue, dur], i) => (
        <span
          key={i}
          className={s.orb}
          aria-hidden="true"
          style={{ '--x': `${x}%`, '--y': `${y}%`, '--size': `${size}px`, '--hue': hue, '--dur': `${dur}s`, '--delay': `${-i * 1.7}s` } as React.CSSProperties}
        />
      ))}
      <p className={s.title}>{labels.title}</p>
    </div>
  )
}
demo.module.css
.scene {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: radial-gradient(ellipse at 50% 120%, oklch(28% 0.04 50), var(--stage-bg));
}

.orb {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--size);
  height: var(--size);
  margin: calc(var(--size) / -2) 0 0 calc(var(--size) / -2);
  border-radius: 50%;
  background: radial-gradient(circle, oklch(80% 0.13 var(--hue)) 0 40%, transparent 70%);
  filter: blur(6px);
  mix-blend-mode: screen;
  opacity: 0.5;
  animation: drift var(--dur) ease-in-out var(--delay) infinite alternate;
}

.scene[data-paused] .orb { animation-play-state: paused; }

@keyframes drift {
  0% { transform: translate(-20px, 10px) scale(0.85); opacity: 0.35; }
  50% { opacity: 0.8; }
  100% { transform: translate(20px, -15px) scale(1.1); opacity: 0.45; }
}

.title {
  position: relative;
  margin: 0;
  font: 600 var(--text-2xl) / 1 var(--font-display);
  letter-spacing: -0.01em;
  color: var(--stage-ink);
}

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

Suggest an idea

Seen a motion or a theme you would like to find here? Describe it, and it opens as a prefilled GitHub issue for you to post.

What are you suggesting?

Needs a GitHub account. Suggestions are public.