spb/svgarden Public
SVGarden — searchable bank of 74 self-contained SVG+CSS animation snippets (svgarden.dev)
HTML 79.2%
Astro 10.3%
JavaScript 6%
CSS 3.7%
Shell 0.8%
1<!--2 ============================================================3 SVGarden — https://www.svgarden.dev4 Author : Simon-Pierre Boucher5 Contact: contact@spboucher.ai6 File : snippets/scroll/scroll-progress-path.html7 Desc : A path draws itself as its container scrolls (scroll-driven animation)8 ============================================================9-->10<!--svgarden11title: Scroll-drawn path12slug: scroll-progress-path13category: scroll14tags: [scroll, draw, progress, scroll-timeline]15difficulty: advanced16techniques: ["animation-timeline: scroll()", "@supports", pathLength, stroke-dashoffset]17how_it_works: >18 animation-timeline: scroll() detaches the keyframes from the clock and binds19 them to scroll progress — scroll(nearest) means "the nearest scrolling20 ancestor", which here is the snippet's own overflow-y box, so the demo is21 fully self-contained. The dashoffset keyframes then map 0%→100% of the22 scroll range onto the classic line-draw trick, and animation-duration: auto23 hands timing control entirely to the timeline. Everything sits inside an24 @supports gate: browsers without scroll-driven animations simply show the25 path fully drawn instead of broken.26support: "Scroll-driven animations need Chrome/Edge 115+ (Firefox behind a flag); unsupported browsers show the path fully drawn, static."27customizable:28 - { var: "--sg-color", label: "Ink", type: color, default: "#7F77DD" }29 - { var: "--sg-size", label: "Box height", type: range, min: 180, max: 400, default: 260, unit: px }30 - { var: "--sg-stroke", label: "Stroke", type: range, min: 1, max: 8, step: 0.5, default: 3, unit: px }31created: 2026-08-1032-->33<div class="sg-scroll-progress-path" style="--sg-color:#7F77DD; --sg-size:260px; --sg-stroke:3px;">34 <div class="sg-scroll-progress-path-track">35 <div class="sg-scroll-progress-path-sticky">36 <svg viewBox="0 0 200 120" aria-hidden="true" focusable="false">37 <path class="sg-scroll-progress-path-ghost" pathLength="100"38 d="M12 90 C 40 20, 60 20, 80 60 C 100 100, 120 100, 140 40 C 150 15, 170 25, 188 45" />39 <path class="sg-scroll-progress-path-line" pathLength="100"40 d="M12 90 C 40 20, 60 20, 80 60 C 100 100, 120 100, 140 40 C 150 15, 170 25, 188 45" />41 </svg>42 <span class="sg-scroll-progress-path-hint">scroll ↓</span>43 </div>44 </div>45</div>46<style>47 .sg-scroll-progress-path {48 width: 100%;49 min-width: 220px;50 height: var(--sg-size);51 overflow-y: scroll;52 border: 1px solid rgba(128, 128, 128, 0.3);53 border-radius: 10px;54 }55 .sg-scroll-progress-path-track {56 height: calc(var(--sg-size) * 3);57 }58 .sg-scroll-progress-path-sticky {59 position: sticky;60 top: 0;61 height: var(--sg-size);62 display: grid;63 place-items: center;64 }65 .sg-scroll-progress-path-sticky svg {66 width: 78%;67 display: block;68 }69 .sg-scroll-progress-path-hint {70 position: absolute;71 right: 12px;72 bottom: 8px;73 font-size: 12px;74 opacity: 0.6;75 }76 .sg-scroll-progress-path-ghost {77 fill: none;78 stroke: rgba(128, 128, 128, 0.25);79 stroke-width: var(--sg-stroke);80 stroke-linecap: round;81 }82 .sg-scroll-progress-path-line {83 fill: none;84 stroke: var(--sg-color);85 stroke-width: var(--sg-stroke);86 stroke-linecap: round;87 stroke-dasharray: 100;88 stroke-dashoffset: 0; /* fallback: fully drawn */89 }90 @supports (animation-timeline: scroll()) {91 .sg-scroll-progress-path-line {92 animation: sg-scroll-progress-path-draw linear both;93 animation-duration: auto;94 animation-timeline: scroll(nearest);95 }96 }97 @keyframes sg-scroll-progress-path-draw {98 from { stroke-dashoffset: 100; }99 to { stroke-dashoffset: 0; }100 }101</style>102