Section colour blend

The page background melts smoothly from one section’s colour into the next.

How it works

Each section declares a background and text colour in data attributes. On scroll, the script finds the pair of sections around the viewport centre and linearly interpolates their RGB values, then paints the body with the result.

Full file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Section colour blend</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; }
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; -webkit-font-smoothing: antialiased; }

body { transition: none; }
section { height: 100vh; display: grid; place-items: center; }
section h2 { font: 900 clamp(3rem, 13vw, 9rem)/1 system-ui, sans-serif; letter-spacing: -.04em; margin: 0; }
</style>
</head>
<body>
<section data-bg="#fff1e6" data-fg="#6d2e46"><h2>Morning</h2></section>
<section data-bg="#a2d2ff" data-fg="#03045e"><h2>Noon</h2></section>
<section data-bg="#ffafcc" data-fg="#590d22"><h2>Afternoon</h2></section>
<section data-bg="#ff7b00" data-fg="#2b0f00"><h2>Sunset</h2></section>
<section data-bg="#10002b" data-fg="#e0aaff"><h2>Night</h2></section>
<script>
const secs = [...document.querySelectorAll('section')];
const hex = h => [1, 3, 5].map(i => parseInt(h.slice(i, i + 2), 16));
const mix = (a, b, t) => 'rgb(' + a.map((v, i) => Math.round(v + (b[i] - v) * t)).join(',') + ')';
const cols = secs.map(s => ({ bg: hex(s.dataset.bg), fg: hex(s.dataset.fg) }));
function update() {
  const pos = (scrollY + innerHeight / 2) / innerHeight - 0.5;
  const i = Math.max(0, Math.min(secs.length - 1, Math.floor(pos)));
  const j = Math.min(secs.length - 1, i + 1);
  const t = Math.max(0, Math.min(1, pos - i));
  document.body.style.background = mix(cols[i].bg, cols[j].bg, t);
  document.body.style.color = mix(cols[i].fg, cols[j].fg, t);
}
addEventListener('scroll', update, { passive: true });
update();
</script>
</body>
</html>

More color effects