<div class="inner">
  <h2>Scroll me</h2>
  <p>
    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;.
  </p>
  <p>
    Using css var to dynamically change css values. In this case the hue inside hsl() is changed.
  </p>
  <p>
    Other fun properties to use this on are opacity and transforms. For example used as an alternative method for parallax.
  </p>
</div>
: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) { 
      cancelAnimationFrame(frame);
    }

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

  } 
};


// 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
storeScroll();
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.