Web design effects

Aurora drift

Two blurred colour blobs drifting on mismatched periods, so the composition never visibly loops. Two pseudo-elements, no images, no canvas.

How it works

Numbers

Blob size
420px / 460px
Blur
90px
Opacity
0.55
Periods
18s / 22s, ease-in-out alternate
Travel
≤80px, scale ≤1.12

Prompt

Paste this into any coding model to get the effect from scratch. It states every number explicitly — vague words like “smooth” or “modern” produce a different result every time.

Create an ambient background using two pseudo-elements on a container. Each is a circle (420px and 460px) filled with a radial-gradient from a pastel colour to transparent at 70%, with filter: blur(90px) and opacity 0.55, positioned so they overflow opposite corners of the container. Animate each with a different period — 18s and 22s, ease-in-out, infinite alternate — moving them by no more than 80px with translate() and scaling to at most 1.12. Animate transform only, never top/left. Set overflow: hidden and isolation: isolate on the container, put the blobs at z-index: -1, and disable both animations under prefers-reduced-motion: reduce.

Source

The whole file. It is what the sample above is running — copy it into an .html file and it works with nothing else.

aurora-drift.html
<!doctype html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Aurora drift</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    min-height: 100vh;
    display: grid; place-items: center;
    background: #fbfbfd;
    font: 600 clamp(22px, 5vw, 34px)/1.1 -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif;
    letter-spacing: -0.025em;
    color: #1d1d1f;
    /* The blobs deliberately overflow the viewport. Without this the page
       grows scrollbars around them. */
    overflow: hidden;
    position: relative;
    isolation: isolate;
  }

  /* Two large blurred blobs, each drifting on its own period.
     The periods are 18s and 22s — deliberately not equal, and not
     multiples of one another. Give both the same duration and the whole
     composition visibly repeats every cycle. */
  body::before, body::after {
    content: "";
    position: absolute; z-index: -1;
    border-radius: 50%;
    filter: blur(90px);
    opacity: 0.55;
    pointer-events: none;
  }
  body::before {
    width: 420px; height: 420px; top: -12%; left: -10%;
    background: radial-gradient(circle, #a6dcf5, transparent 70%);
    animation: drift-a 18s ease-in-out infinite alternate;
  }
  body::after {
    width: 460px; height: 460px; bottom: -14%; right: -12%;
    background: radial-gradient(circle, #f5cde8, transparent 70%);
    animation: drift-b 22s ease-in-out infinite alternate;
  }

  /* Animate transform only. Moving the blob by changing top/left would
     re-run the 90px blur every frame; a transform hands the already-blurred
     layer to the compositor and merely moves it. */
  @keyframes drift-a { to { transform: translate(70px, 50px) scale(1.12); } }
  @keyframes drift-b { to { transform: translate(-80px, -60px) scale(1.08); } }

  @media (prefers-reduced-motion: reduce) {
    body::before, body::after { animation: none; }
  }
</style>

<p>Quiet light, moving slowly.</p>

Where it breaks