<div class="inner">
  <h2>Scroll me</h2>
    Code based on CSS-tricks article &quot;<a href="https://css-tricks.com/styling-based-on-scroll-position/">Styling Based on Scroll Position</a>&quot;.
    Using css var to dynamically change css values. In this case the hue inside hsl() is changed.
    Other fun properties to use this on are opacity and transforms. For example used as an alternative method for parallax.
:root {
  --scrollpos: 0;
body {
  min-height: 600vh;
  background-color: hsl(calc(var(--scrollpos) * 3.6), 100%, 50%);
.inner {
  position: fixed;
View Compiled
// The debounce function receives our function as a parameter
const debounce = (fn) => {

  // This holds the requestAnimationFrame reference, so we can cancel it if we wish
  let frame;

  // The debounce function returns a new function that can receive a variable number of arguments
  return (...params) => {
    // If the frame variable has been defined, clear it now, and queue for next frame
    if (frame) { 

    // Queue our function call for the next frame
    frame = requestAnimationFrame(() => {
      // Call our function and pass any params we received


// Reads out the scroll position and stores it in the data attribute
// so we can use it in our stylesheets
const storeScroll = () => {
  let perc = window.scrollY / (document.body.clientHeight - window.innerHeight) * 100;
  document.documentElement.setAttribute('style', `--scrollpos: ${perc}`);

// Listen for new scroll events, here we debounce our `storeScroll` function
document.addEventListener('scroll', debounce(storeScroll), { passive: true });

// Update scroll position for first time
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.