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-counter-gauge.html7 Desc : Circular gauge that fills with scroll position8 ============================================================9-->10<!--svgarden11title: Scroll gauge12slug: scroll-counter-gauge13category: scroll14tags: [scroll, gauge, progress, scroll-timeline]15difficulty: advanced16techniques: ["animation-timeline: scroll()", pathLength, scale-property, "@supports"]17how_it_works: >18 Two animations ride the same scroll timeline: the arc's stroke-dashoffset19 runs 100→0 (pathLength="100" makes the circumference exactly 100, so offset20 equals "percent unscrolled"), while the independent scale property breathes21 the dial from 0.85 to 1 — using scale instead of transform means it can't22 collide with the −90° rotation that starts the arc at twelve o'clock.23 Because both declare animation-duration: auto and scroll(nearest), the24 box's own scrollbar is the only clock. Unsupported browsers skip the25 @supports block and simply show the gauge full.26support: "Scroll-driven animations need Chrome/Edge 115+; other browsers show the gauge fully filled, static."27customizable:28 - { var: "--sg-color", label: "Color", type: color, default: "#7F77DD" }29 - { var: "--sg-size", label: "Box height", type: range, min: 180, max: 400, default: 260, unit: px }30 - { var: "--sg-thick", label: "Thickness", type: range, min: 4, max: 14, default: 8, unit: px }31created: 2026-08-1032-->33<div class="sg-scroll-counter-gauge" style="--sg-color:#7F77DD; --sg-size:260px; --sg-thick:8px;">34 <div class="sg-scroll-counter-gauge-track">35 <div class="sg-scroll-counter-gauge-sticky">36 <svg viewBox="0 0 100 100" aria-hidden="true" focusable="false">37 <circle class="sg-scroll-counter-gauge-rail" cx="50" cy="50" r="42" pathLength="100" />38 <circle class="sg-scroll-counter-gauge-arc" cx="50" cy="50" r="42" pathLength="100" />39 <text class="sg-scroll-counter-gauge-label" x="50" y="55">scroll</text>40 </svg>41 <span class="sg-scroll-counter-gauge-hint">scroll ↓</span>42 </div>43 </div>44</div>45<style>46 .sg-scroll-counter-gauge {47 width: 100%;48 min-width: 200px;49 height: var(--sg-size);50 overflow-y: scroll;51 border: 1px solid rgba(128, 128, 128, 0.3);52 border-radius: 10px;53 }54 .sg-scroll-counter-gauge-track {55 height: calc(var(--sg-size) * 3);56 }57 .sg-scroll-counter-gauge-sticky {58 position: sticky;59 top: 0;60 height: var(--sg-size);61 display: grid;62 place-items: center;63 }64 .sg-scroll-counter-gauge-sticky svg {65 width: min(55%, calc(var(--sg-size) * 0.65));66 display: block;67 }68 .sg-scroll-counter-gauge-hint {69 position: absolute;70 right: 12px;71 bottom: 8px;72 font-size: 12px;73 opacity: 0.6;74 }75 .sg-scroll-counter-gauge-rail,76 .sg-scroll-counter-gauge-arc {77 fill: none;78 stroke: var(--sg-color);79 stroke-width: var(--sg-thick);80 stroke-linecap: round;81 transform: rotate(-90deg);82 transform-origin: 50% 50%;83 }84 .sg-scroll-counter-gauge-rail { opacity: 0.15; }85 .sg-scroll-counter-gauge-arc {86 stroke-dasharray: 100;87 stroke-dashoffset: 0; /* fallback: full */88 }89 .sg-scroll-counter-gauge-label {90 font-family: inherit;91 font-size: 13px;92 font-weight: 600;93 fill: var(--sg-color);94 text-anchor: middle;95 }96 @supports (animation-timeline: scroll()) {97 .sg-scroll-counter-gauge-arc {98 animation: sg-scroll-counter-gauge-fill linear both;99 animation-duration: auto;100 animation-timeline: scroll(nearest);101 }102 .sg-scroll-counter-gauge-sticky svg {103 animation: sg-scroll-counter-gauge-breathe linear both;104 animation-duration: auto;105 animation-timeline: scroll(nearest);106 }107 }108 @keyframes sg-scroll-counter-gauge-fill {109 from { stroke-dashoffset: 100; }110 to { stroke-dashoffset: 0; }111 }112 @keyframes sg-scroll-counter-gauge-breathe {113 from { scale: 0.85; }114 to { scale: 1; }115 }116</style>117