SPB Git

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%
3.9 KB · 112 lines html
Raw Blame History
1<!--2  ============================================================3  SVGarden — https://www.svgarden.dev4  Author : Simon-Pierre Boucher5  Contact: contact@spboucher.ai6  File   : snippets/scroll/scroll-rotate-badge.html7  Desc   : Circular text badge that spins with scroll progress8  ============================================================9-->10<!--svgarden11title: Scroll-spun badge12slug: scroll-rotate-badge13category: scroll14tags: [scroll, badge, textPath, rotate]15difficulty: intermediate16techniques: ["animation-timeline: scroll()", textPath, "@supports", progressive-enhancement]17how_it_works: >18  The round label is ordinary textPath typography on a hidden circle; the19  motion is one rotate keyframe used twice. By default it runs on the regular20  clock (a slow infinite spin), then an @supports block rebinds the very same21  keyframes to animation-timeline: scroll(nearest), so the badge's angle22  becomes a direct readout of how far the box is scrolled — flick fast and it23  whips around, creep and it crawls. Reusing one @keyframes for both the24  fallback and the enhancement is the cleanest progressive-enhancement shape25  for scroll-driven work.26support: "Scroll-linked rotation needs Chrome/Edge 115+; other browsers gracefully fall back to a slow time-based spin."27customizable:28  - { var: "--sg-color",    label: "Color",            type: color, default: "#7F77DD" }29  - { var: "--sg-size",     label: "Box height",       type: range, min: 160, max: 360, default: 240, unit: px }30  - { var: "--sg-duration", label: "Fallback spin",    type: range, min: 4, max: 30, default: 14, unit: s }31created: 2026-08-1032-->33<div class="sg-scroll-rotate-badge" style="--sg-color:#7F77DD; --sg-size:240px; --sg-duration:14s;">34  <div class="sg-scroll-rotate-badge-track">35    <div class="sg-scroll-rotate-badge-sticky">36      <svg viewBox="0 0 100 100" aria-hidden="true" focusable="false">37        <defs>38          <path id="sg-scroll-rotate-badge-o" d="M50 50 m-36 0 a36 36 0 1 1 72 0 a36 36 0 1 1 -72 0" />39        </defs>40        <g class="sg-scroll-rotate-badge-spin">41          <text class="sg-scroll-rotate-badge-text">42            <textPath href="#sg-scroll-rotate-badge-o">scroll · scroll · scroll · scroll ·&#160;</textPath>43          </text>44        </g>45        <path class="sg-scroll-rotate-badge-arrow" d="M50 40 V60 M43 54 L50 61 L57 54" />46      </svg>47      <span class="sg-scroll-rotate-badge-hint">scroll ↓</span>48    </div>49  </div>50</div>51<style>52  .sg-scroll-rotate-badge {53    width: 100%;54    min-width: 200px;55    height: var(--sg-size);56    overflow-y: scroll;57    border: 1px solid rgba(128, 128, 128, 0.3);58    border-radius: 10px;59  }60  .sg-scroll-rotate-badge-track {61    height: calc(var(--sg-size) * 3);62  }63  .sg-scroll-rotate-badge-sticky {64    position: sticky;65    top: 0;66    height: var(--sg-size);67    display: grid;68    place-items: center;69  }70  .sg-scroll-rotate-badge-sticky svg {71    width: min(60%, calc(var(--sg-size) * 0.7));72    display: block;73    overflow: visible;74  }75  .sg-scroll-rotate-badge-hint {76    position: absolute;77    right: 12px;78    bottom: 8px;79    font-size: 12px;80    opacity: 0.6;81  }82  .sg-scroll-rotate-badge-text {83    font-family: inherit;84    font-size: 10.5px;85    font-weight: 600;86    letter-spacing: 2.5px;87    fill: var(--sg-color);88  }89  .sg-scroll-rotate-badge-arrow {90    fill: none;91    stroke: var(--sg-color);92    stroke-width: 2.5;93    stroke-linecap: round;94    stroke-linejoin: round;95  }96  .sg-scroll-rotate-badge-spin {97    transform-origin: 50% 50%;98    animation: sg-scroll-rotate-badge-turn var(--sg-duration) linear infinite;99  }100  @supports (animation-timeline: scroll()) {101    .sg-scroll-rotate-badge-spin {102      animation: sg-scroll-rotate-badge-turn linear both;103      animation-duration: auto;104      animation-timeline: scroll(nearest);105    }106  }107  @keyframes sg-scroll-rotate-badge-turn {108    from { transform: rotate(0turn); }109    to   { transform: rotate(1turn); }110  }111</style>112