Combining three techniques
This infographic layers three SVG capabilities on top of each other. A <linearGradient> fills the chart bars with an orange-to-red sweep. CSS @keyframes animations grow those bars from zero height and draw a progress ring around a circular counter. A JavaScript requestAnimationFrame loop increments the number inside the ring, timing its count to match the ring draw animation. Together they make a self-contained, accessible SVG that communicates data through motion.
Defining the gradient
Gradients live in <defs> and are referenced by id. The two stop colors here are drawn from the on-palette range — amber (#f0a500) fading to red (#d6452c). Setting gradientUnits="objectBoundingBox" (the SVG default) means gradient coordinates are expressed as fractions of each shape's own bounding box — so x1="0" y1="0" x2="0" y2="1" always runs top-to-bottom across whatever shape the gradient fills, regardless of that shape's position or height.
Apply the gradient with fill="url(#infographic-bar-grad)" — the same syntax that also works for stroke.
CSS animation: growing bars and the ring draw
Bars scale from zero height using transform: scaleY(0) → scaleY(1) with transform-origin: center bottom pinned at the baseline. A staggered animation-delay creates a sequential reveal.
The progress ring uses the stroke-dashoffset trick: set stroke-dasharray equal to the circle's circumference (2πr), then animate stroke-dashoffset from the full circumference down to the offset representing the remaining percentage. The visible dash grows as the offset shrinks.
JavaScript: the counting animation
A <text> element in the SVG displays a number that counts up from 0 to 78 using requestAnimationFrame. The counter respects prefers-reduced-motion — if the preference is set, it skips straight to the final value without any looping.
Live demo
Load or replay the demo to watch the bars grow, the ring draw, and the counter count up. The Replay button restarts all animations. If you have "Reduce Motion" enabled in your OS accessibility settings, the counter jumps straight to the final value and the CSS animations are disabled.
Accessibility: making the infographic readable
Each SVG carries role="img" so assistive technology presents it as a single graphic. The first child of each SVG is a <title> (the accessible name), followed by a <desc> with a full prose summary of the data. A screen reader user gets the complete information without needing to navigate the individual shapes.
The prefers-reduced-motion media query appears in two places. In CSS it sets animation: none on every animated element. In JavaScript the counter function checks window.matchMedia('(prefers-reduced-motion: reduce)').matches before starting the requestAnimationFrame loop — if motion is reduced, it writes the final value directly. This dual guard is necessary because CSS cannot stop a JavaScript animation, and JavaScript cannot suppress CSS animations by itself.
The stroke-dashoffset technique
The progress ring relies on a classic SVG trick. A circle has a circumference of 2πr. Setting stroke-dasharray equal to the circumference creates a dash that exactly wraps the circle. Setting stroke-dashoffset to the full circumference shifts the dash entirely off the visible start of the stroke — making it invisible. Animating the offset back toward zero causes the dash to sweep visibly around the ring. Stopping at an offset that equals circumference × (1 - fraction) leaves exactly the desired percentage filled.