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/text-fx/text-variable-weight-wave.html7 Desc : A wave of font-weight rolling across letters via @property8 ============================================================9-->10<!--svgarden11title: Variable-weight wave12slug: text-variable-weight-wave13category: text-fx14tags: [text, variable-font, property, stagger]15difficulty: advanced16techniques: ["@property", font-variation-settings, --sg-i-index-stagger, "@supports"]17how_it_works: >18 Custom properties normally interpolate as raw strings, so animating one just19 snaps between keyframes. Registering it with @property and syntax:'<number>'20 tells the engine it is a real number, making it tween smoothly — and here that21 animated number is piped straight into font-variation-settings "wght", so the22 glyph skeleton itself thickens and relaxes. Each letter carries its position23 in a --sg-i variable, and a negative animation-delay computed from it phases24 the shared keyframe into a traveling wave. Inside @supports the effect is25 gated: browsers without @property (or without a variable system font) simply26 show the text at a steady weight.27support: >28 Needs @property and font-variation-settings (Chrome 85+, Safari 16.4+,29 Firefox 128+) plus a variable system font such as SF Pro or Segoe UI30 Variable; elsewhere the text renders at a static weight.31customizable:32 - { var: "--sg-color", label: "Color", type: color, default: "#7F77DD" }33 - { var: "--sg-size", label: "Font size", type: range, min: 20, max: 72, default: 42, unit: px }34 - { var: "--sg-duration", label: "Speed", type: range, min: 0.8, max: 5, step: 0.1, default: 2, unit: s }35created: 2026-08-1036-->37<div class="sg-text-variable-weight-wave" aria-label="flexible" style="--sg-color:#7F77DD; --sg-size:42px; --sg-duration:2s;">38 <span class="sg-text-variable-weight-wave-ch" style="--sg-i:0" aria-hidden="true">f</span><span class="sg-text-variable-weight-wave-ch" style="--sg-i:1" aria-hidden="true">l</span><span class="sg-text-variable-weight-wave-ch" style="--sg-i:2" aria-hidden="true">e</span><span class="sg-text-variable-weight-wave-ch" style="--sg-i:3" aria-hidden="true">x</span><span class="sg-text-variable-weight-wave-ch" style="--sg-i:4" aria-hidden="true">i</span><span class="sg-text-variable-weight-wave-ch" style="--sg-i:5" aria-hidden="true">b</span><span class="sg-text-variable-weight-wave-ch" style="--sg-i:6" aria-hidden="true">l</span><span class="sg-text-variable-weight-wave-ch" style="--sg-i:7" aria-hidden="true">e</span>39</div>40<style>41 @property --sg-tvww-wgt {42 syntax: '<number>';43 inherits: false;44 initial-value: 400;45 }46 .sg-text-variable-weight-wave {47 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Text', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;48 font-size: var(--sg-size);49 color: var(--sg-color);50 letter-spacing: 0.02em;51 display: inline-flex;52 }53 .sg-text-variable-weight-wave-ch {54 font-weight: 550;55 }56 @supports (font-variation-settings: "wght" 500) {57 .sg-text-variable-weight-wave-ch {58 animation: sg-text-variable-weight-wave-roll var(--sg-duration) ease-in-out infinite;59 animation-delay: calc(var(--sg-i) * var(--sg-duration) / -8);60 font-variation-settings: "wght" var(--sg-tvww-wgt);61 font-weight: normal;62 }63 }64 @keyframes sg-text-variable-weight-wave-roll {65 0%, 100% { --sg-tvww-wgt: 260; }66 50% { --sg-tvww-wgt: 840; }67 }68</style>69