<div class="blobs">
  <div class="blob"></div>
  <div class="blob"></div>
  <div class="blob"></div>
  <div class="blob"></div>
  <div class="blob"></div>
  <div class="blob"></div>
  <div class="blob"></div>
</div>

<h2>Smooth liquid background effect</h2>
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

:root {
  --cr-main-1: #2ac9de;
  --cr-main-2: #f087f4;
  --cr-1: color-mix(in srgb, var(--cr-main-1), var(--cr-main-2) 20%);
  --cr-2: color-mix(in srgb, var(--cr-main-1), var(--cr-main-2) 35%);
  --cr-3: color-mix(in srgb, var(--cr-main-1), var(--cr-main-2) 50%);
  --cr-4: color-mix(in srgb, var(--cr-main-1), var(--cr-main-2) 65%);
  --cr-5: color-mix(in srgb, var(--cr-main-1), var(--cr-main-2) 80%);
}

html,
body {
  font-family: "Poppins", sans-serif;
  height: 100%;
}

body {
  display: grid;
  place-content: center;
  background: whitesmoke;
}

.blobs {
  position: fixed;
  z-index: -1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  filter: blur(140px);
}

.blob {
  width: max(240px, 28vw);
  aspect-ratio: 1;
  border-radius: 50%;
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: center;
}

.blob:nth-of-type(1) {
  background: var(--cr-main-1);
}

.blob:nth-of-type(2) {
  background: var(--cr-main-2);
}

.blob:nth-of-type(3) {
  background: var(--cr-1);
}

.blob:nth-of-type(4) {
  background: whitesmoke;
}

.blob:nth-of-type(5) {
  background: var(--cr-3);
}

.blob:nth-of-type(6) {
  background: var(--cr-4);
}

.blob:nth-of-type(7) {
  background: var(--cr-2);
}

h2 {
  font-size: clamp(24px, 6vw, 64px);
  max-width: 400px;
  text-align: center;
  font-weight: bold;
  text-transform: uppercase;
  opacity: 0.8;
  mix-blend-mode: overlay;
}
const MIN_SPEED = 0.5;
const MAX_SPEED = 2;

function randomNumber(min, max) {
  return Math.random() * (max - min) + min;
}

class Blob {
  constructor(el) {
    this.el = el;
    const boundingRect = this.el.getBoundingClientRect();
    this.size = boundingRect.width;
    // 隨機初始位置
    this.initialX = randomNumber(0, window.innerWidth - this.size);
    this.initialY = randomNumber(0, window.innerHeight - this.size);
    this.el.style.top = `${this.initialY}px`;
    this.el.style.left = `${this.initialX}px`;
    // 速度
    this.vx =
      randomNumber(MIN_SPEED, MAX_SPEED) * (Math.random() > 0.5 ? 1 : -1);
    this.vy =
      randomNumber(MIN_SPEED, MAX_SPEED) * (Math.random() > 0.5 ? 1 : -1);
    this.x = this.initialX;
    this.y = this.initialY;
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;
    if (this.x >= window.innerWidth - this.size) {
      this.x = window.innerWidth - this.size;
      this.vx *= -1;
    }
    if (this.y >= window.innerHeight - this.size) {
      this.y = window.innerHeight - this.size;
      this.vy *= -1;
    }
    if (this.x <= 0) {
      this.x = 0;
      this.vx *= -1;
    }
    if (this.y <= 0) {
      this.y = 0;
      this.vy *= -1;
    }

    this.el.style.transform = `translate(${this.x - this.initialX}px, ${
      this.y - this.initialY
    }px)`;
  }
}

function initBlobs() {
  const blobEls = document.querySelectorAll(".blob");
  const blobs = Array.from(blobEls).map((blobEl) => new Blob(blobEl));

  function update() {
    requestAnimationFrame(update);
    blobs.forEach((blob) => blob.update());
  }
  requestAnimationFrame(update);
}

initBlobs();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.