<input type="range" id="range">

<p style="position: absolute;bottom: 0;left: 0;z-index: 1;">Forked from <a href="https://codepen.io/kizu/pen/RwvLBqM">https://codepen.io/kizu/pen/RwvLBqM</a> by Roman Komarov</p>
@layer demo {
  @supports (timeline-scope: --foo) {
    input[type="range"] {
      /* only destroy the default look and do a gradient trick if @supports */
      appearance: none;
      background: none;
      inline-size: 75vw;
      
      /* animate an @property from 0-100% */
      animation: --range-observer linear reverse;
      
      /* drive the animation to the thumb intersection with the input track */
      /* track is a timeline because overflow-x is on it, and the thumb is a child of track */
      animation-timeline: --range-thumb;
      
      /* this allows a parent to observe the timeline of a child */
      timeline-scope: --range-thumb;
      
      /* thumb creates a timeline of its inline intersection */
      &::-webkit-slider-thumb {
        view-timeline: --range-thumb inline;
      }

      /* this width = the animation range = the input's inline-size */
      &::-webkit-slider-runnable-track {
        /* turn track into a scrollport for intersection observation */
        overflow-x: auto;
        /* use the @property progress value in a gradient */
        background: 
          linear-gradient(to right in oklab, 
            oklch(55% .4 350),
            /* --range-value stops the gradient at the thumb position */
            oklch(90% .3 95) var(--range-value, 50%), 
            /* and finishes the gradient with a solid track fill */
            oklch(from Canvas calc(l * .5) c h) 0
          );
        /* all that work just to set a % for a gradient stop.. 😅 */
      }
    }
  }
  
  @property --range-value {
    syntax: "<percentage>";
    initial-value: 0%;
    inherits: true;
  }
  
  @keyframes --range-observer {
    to { --range-value: 100% }
  }
  
  input[type="range"] {
    --size: 24px;
    
    &::-webkit-slider-thumb {
      appearance: none;
      cursor: pointer;
      width: var(--size);
      height: var(--size);
      border-radius: 1e3px;
      background-color: white;
    }
    
    &::-webkit-slider-runnable-track {
      /* this gives the thumb breathing room by shrinking and scootin down a bit */
      background-size: 100% calc(var(--size) / 2);
      background-position-y: calc(var(--size) / 4);
      background-repeat: no-repeat;
    }
    
    &::-moz-range-thumb {
      appearance: none;
      width: 24px;
      height: 24px;
      border-radius: 1e3px;
      background-color: CanvasText;
    }
  }
}

@layer demo.support {
  * {
    box-sizing: border-box;
    margin: 0;
  }

  html {
    block-size: 100%;
    color-scheme: dark light;
      
    @media (prefers-color-scheme: light) {
      background-color: #ddd;
    }
  }

  body {
    min-block-size: 100%;
    font-family: system-ui, sans-serif;
    display: grid;
    place-content: center;
  }
}

body::after {
  content: "Using JS; try in Chrome";
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
}

@supports (timeline-scope: --foo) {
  body::after {
    content: "Using Scroll-driven animations";
  }  
}
if (!CSS.supports('timeline-scope', '--foo')) {
  range.oninput = () =>
    document.body.style.setProperty('--range-value', range.value + '%')
}

View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.