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%
4.7 KB · 106 lines html
Raw Blame History
1<!--2  ============================================================3  SVGarden — https://www.svgarden.dev4  Author : Simon-Pierre Boucher5  Contact: contact@spboucher.ai6  File   : snippets/charts/chart-bar-race.html7  Desc   : Horizontal bars racing to their values with spring stagger8  ============================================================9-->10<!--svgarden11title: Bar race12slug: chart-bar-race13category: charts14tags: [chart, bars, stagger, spring]15difficulty: intermediate16techniques: ["--sg-i index variables", "scaleX", "cubic-bezier() overshoot", "animation-delay"]17how_it_works: >18  Each bar is drawn at its final width in the markup — the data mapping is plain19  linear scaling, width = value × 1.6 units — and then compressed to zero with20  transform: scaleX(0), so the animation never has to know the value. The race21  feel comes from two ingredients: every row carries its rank in a --sg-i custom22  property, and one shared rule computes animation-delay: calc(var(--sg-i) × 18%23  of the duration), so adding a sixth bar means adding one line of markup, not24  one line of CSS. The overshoot is a cubic-bezier whose second control point25  rises above 1, making each bar shoot slightly past its value and settle back26  like a spring. Value labels reuse the same delay math plus most of the grow27  time, so each number pops in just as its bar arrives.28customizable:29  - { var: "--sg-color",    label: "Bar color", type: color, default: "#7F77DD" }30  - { var: "--sg-size",     label: "Width",     type: range, min: 160, max: 420, default: 260, unit: px }31  - { var: "--sg-duration", label: "Speed",     type: range, min: 0.4, max: 2.5, step: 0.1, default: 0.9, unit: s }32created: 2026-08-1033-->34<div class="sg-chart-bar-race" style="--sg-color:#7F77DD; --sg-size:260px; --sg-duration:0.9s;">35  <svg viewBox="0 0 240 118" role="img" aria-label="Bar chart: Python 92, Rust 78, Go 64, TypeScript 55, C 38">36    <title>Language popularity bar chart</title>37    <g class="sg-chart-bar-race-row" style="--sg-i:0">38      <text class="sg-chart-bar-race-name" x="48" y="20">Python</text>39      <rect class="sg-chart-bar-race-bar" x="54" y="10" width="147" height="12" rx="3" />40      <text class="sg-chart-bar-race-val" x="206" y="20">92</text>41    </g>42    <g class="sg-chart-bar-race-row" style="--sg-i:1">43      <text class="sg-chart-bar-race-name" x="48" y="42">Rust</text>44      <rect class="sg-chart-bar-race-bar" x="54" y="32" width="125" height="12" rx="3" />45      <text class="sg-chart-bar-race-val" x="184" y="42">78</text>46    </g>47    <g class="sg-chart-bar-race-row" style="--sg-i:2">48      <text class="sg-chart-bar-race-name" x="48" y="64">Go</text>49      <rect class="sg-chart-bar-race-bar" x="54" y="54" width="102" height="12" rx="3" />50      <text class="sg-chart-bar-race-val" x="161" y="64">64</text>51    </g>52    <g class="sg-chart-bar-race-row" style="--sg-i:3">53      <text class="sg-chart-bar-race-name" x="48" y="86">TypeScript</text>54      <rect class="sg-chart-bar-race-bar" x="54" y="76" width="88" height="12" rx="3" />55      <text class="sg-chart-bar-race-val" x="147" y="86">55</text>56    </g>57    <g class="sg-chart-bar-race-row" style="--sg-i:4">58      <text class="sg-chart-bar-race-name" x="48" y="108">C</text>59      <rect class="sg-chart-bar-race-bar" x="54" y="98" width="61" height="12" rx="3" />60      <text class="sg-chart-bar-race-val" x="120" y="108">38</text>61    </g>62  </svg>63</div>64<style>65  .sg-chart-bar-race {66    width: var(--sg-size);67  }68  .sg-chart-bar-race svg {69    display: block;70    width: 100%;71    font-family: inherit;72  }73  .sg-chart-bar-race-name {74    font-size: 10px;75    text-anchor: end;76    fill: currentColor;77    opacity: 0.75;78  }79  .sg-chart-bar-race-bar {80    fill: var(--sg-color);81    transform-box: fill-box;82    transform-origin: left center;83    animation: sg-chart-bar-race-grow var(--sg-duration) cubic-bezier(0.3, 1.35, 0.5, 1) both;84    animation-delay: calc(var(--sg-i) * var(--sg-duration) * 0.18);85  }86  .sg-chart-bar-race-row:nth-of-type(2) .sg-chart-bar-race-bar { opacity: 0.85; }87  .sg-chart-bar-race-row:nth-of-type(3) .sg-chart-bar-race-bar { opacity: 0.7; }88  .sg-chart-bar-race-row:nth-of-type(4) .sg-chart-bar-race-bar { opacity: 0.55; }89  .sg-chart-bar-race-row:nth-of-type(5) .sg-chart-bar-race-bar { opacity: 0.4; }90  .sg-chart-bar-race-val {91    font-size: 10px;92    font-weight: 600;93    fill: currentColor;94    animation: sg-chart-bar-race-fade 0.3s ease both;95    animation-delay: calc(var(--sg-i) * var(--sg-duration) * 0.18 + var(--sg-duration) * 0.75);96  }97  @keyframes sg-chart-bar-race-grow {98    from { transform: scaleX(0); }99    to   { transform: scaleX(1); }100  }101  @keyframes sg-chart-bar-race-fade {102    from { opacity: 0; }103    to   { opacity: 1; }104  }105</style>106