Lead with one giant number
The simplest infographic element: a single statistic blown up large with a short label. It anchors a section and gives readers one thing to remember.
HTML & CSS
<div class="big-stat">
<p class="num">73%</p>
<p class="label">of learners finish the course</p>
<p class="sub">based on 2,400 students · 2026</p>
</div>
.num { font-size: clamp(3rem, 12vw, 5rem); font-weight: 800; color: #ec4899; line-height: 1; }
.label { font-size: 1rem; color: #475569; font-weight: 600; margin-top: 6px; }
.sub { font-size: .82rem; color: #94a3b8; margin-top: 4px; }
When to use: the headline figure of a report or hero — one number you want to stick.
A row of key numbers with icons
Three or four stats side by side, each with an icon, value, and label. A responsive grid wraps them on small screens.
HTML
<div class="grid">
<div class="stat">
<div class="icon" style="background:#ec4899;">👥</div>
<div class="num" data-target="12000" data-suffix="k">0</div>
<div class="lbl">Students</div>
</div>
<div class="stat">
<div class="icon" style="background:#8b5cf6;">📖</div>
<div class="num" data-target="86">0</div>
<div class="lbl">Courses</div>
</div>
<div class="stat">
<div class="icon" style="background:#0ea5e9;">🎓</div>
<div class="num" data-target="9400" data-suffix="k">0</div>
<div class="lbl">Certificates</div>
</div>
<div class="stat">
<div class="icon" style="background:#22c55e;">⭐</div>
<div class="num" data-target="4.8">0</div>
<div class="lbl">Avg. rating</div>
</div>
</div>
CSS
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 16px; text-align: center; }
.stat .icon { width: 50px; height: 50px; border-radius: 14px; display: grid; place-items: center;
margin: 0 auto 10px; font-size: 1.5rem; color: #fff; }
.stat .num { font-size: 1.9rem; font-weight: 800; color: #0f172a; line-height: 1; }
.stat .lbl { font-size: .8rem; color: #64748b; font-weight: 600; margin-top: 4px; }
JavaScript — count up on scroll-into-view
// Animates each .stat .num from 0 to data-target when scrolled into view.
const counters = document.querySelectorAll('.stat .num[data-target]');
function format(n, target, suffix) {
const decimals = String(target).indexOf('.') > -1 ? 1 : 0;
if (suffix === 'k') return (n / 1000).toFixed(n < 10000 ? 1 : 0).replace(/\.0$/, '') + 'k';
if (decimals) return n.toFixed(1);
return Math.round(n).toString();
}
function animate(el) {
const target = parseFloat(el.dataset.target);
const suffix = el.dataset.suffix || '';
const duration = 1400;
let start = null;
function step(t) {
if (start === null) start = t;
const p = Math.min((t - start) / duration, 1);
const eased = 1 - Math.pow(1 - p, 3);
el.textContent = format(target * eased, target, suffix);
if (p < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
const io = new IntersectionObserver((entries) => {
entries.forEach((e) => {
if (e.isIntersecting) { animate(e.target); io.unobserve(e.target); }
});
}, { threshold: 0.4 });
counters.forEach((c) => io.observe(c));
When to use: a quick “by the numbers” strip. The JS above turns each data-target into a smooth count-up using an IntersectionObserver.
Show a proportion as a ring
A conic-gradient fills the ring to a percentage; a white circle on top makes the hole. Change one variable (--p) per donut — no SVG, no JavaScript.
Completion
Mobile users
Satisfaction
HTML & CSS
<div class="donuts">
<div class="donut-item">
<div class="donut" style="--p:73; --c:#ec4899"><span>73%</span></div>
<p class="cap">Completion</p>
</div>
<div class="donut-item">
<div class="donut" style="--p:48; --c:#8b5cf6"><span>48%</span></div>
<p class="cap">Mobile users</p>
</div>
<div class="donut-item">
<div class="donut" style="--p:91; --c:#22c55e"><span>91%</span></div>
<p class="cap">Satisfaction</p>
</div>
</div>
.donuts { display: flex; gap: 26px; flex-wrap: wrap; justify-content: center; }
.donut-item { text-align: center; }
.donut { width: 120px; height: 120px; border-radius: 50%; display: grid; place-items: center;
background: conic-gradient(var(--c) calc(var(--p) * 1%), #e5e7eb 0); }
.donut span { width: 88px; height: 88px; border-radius: 50%; background: #fff;
display: grid; place-items: center; font-weight: 800; color: #0f172a; } /* the hole */
.cap { font-size: .8rem; color: #64748b; margin-top: 8px; }
When to use: a single proportion (one part of a whole). For multiple slices, use the pie chart instead.
Compare values at a glance
Labelled horizontal bars make sizes easy to compare — bar length encodes the value. Each bar is a track with a coloured fill set by width.
HTML & CSS
<div class="bars">
<div class="bar">
<div class="top"><span>HTML</span><span>92%</span></div>
<div class="track"><div class="fill" style="width:92%;background:#ec4899;"></div></div>
</div>
<div class="bar">
<div class="top"><span>CSS</span><span>78%</span></div>
<div class="track"><div class="fill" style="width:78%;background:#8b5cf6;"></div></div>
</div>
<div class="bar">
<div class="top"><span>JavaScript</span><span>64%</span></div>
<div class="track"><div class="fill" style="width:64%;background:#0ea5e9;"></div></div>
</div>
</div>
.bars { display: grid; gap: 12px; max-width: 460px; }
.top { display: flex; justify-content: space-between; font-size: .82rem; color: #334155; font-weight: 600; margin-bottom: 4px; }
.track { background: #e5e7eb; border-radius: 999px; height: 18px; overflow: hidden; }
.fill { height: 100%; border-radius: 999px; background: #ec4899; transition: width 1s ease; }
JavaScript — reveal each bar on scroll-into-view
// Tweens each .fill from 0% to data-fill% when the bar scrolls into view.
// The CSS transition handles the actual animation.
const fills = document.querySelectorAll('.bar .fill[data-fill]');
// Set everyone to 0 first
fills.forEach((f) => { f.style.width = '0%'; });
const io = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const fill = entry.target;
requestAnimationFrame(() => { fill.style.width = fill.dataset.fill + '%'; });
io.unobserve(fill);
}
});
}, { threshold: 0.4 });
fills.forEach((f) => io.observe(f));
When to use: skill levels, survey results, “us vs. them” comparisons. For axes and gridlines, see the bar graph.
Walk through a sequence
Numbered circles joined by a line show an ordered process — “how it works” in three or four steps. The connecting line is a pseudo-element behind each circle.
Plan
Sketch your idea
Build
Write the code
Test
Check it works
Ship
Deploy it live
CSS — the connecting line
.step { flex: 1; text-align: center; position: relative; }
.step .circle { width: 46px; height: 46px; border-radius: 50%; background: #ec4899; color: #fff;
display: grid; place-items: center; margin: 0 auto; position: relative; z-index: 1; }
.step:not(:last-child)::after { /* line to the next step */
content: ""; position: absolute; top: 23px; left: 50%; width: 100%; height: 3px; background: #f9a8d4;
}
When to use: onboarding, “how it works,” recipes — any ordered set of stages.
Events along a vertical line
A vertical line with dated dots tells a story over time — company history, a roadmap, a project log. The line is one pseudo-element; each event places a dot on it.
CSS
.timeline { position: relative; padding-left: 28px; }
.timeline::before { content: ""; position: absolute; left: 8px; top: 0; bottom: 0; width: 3px; background: #f9a8d4; }
.event::before { content: ""; position: absolute; left: -24px; width: 13px; height: 13px;
border-radius: 50%; background: #ec4899; } /* the dot */
When to use: history, roadmaps, step-by-step stories with dates. For an interactive horizontal version see Timeline Lab.
Bite-size facts with icons
When the data is qualitative, not numeric, icon + headline + sentence cards keep it scannable. A responsive grid lets them flow.
HTML
<div class="facts">
<div class="fact">
<i class="icon">🌿</i>
<div><p class="title">Eco-friendly</p><p>Runs on 100% renewable energy.</p></div>
</div>
<div class="fact">
<i class="icon">🌎</i>
<div><p class="title">Worldwide</p><p>Learners in 36 countries.</p></div>
</div>
<div class="fact">
<i class="icon">🕐</i>
<div><p class="title">Self-paced</p><p>Learn on your own schedule.</p></div>
</div>
</div>
.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; }
.fact { display: flex; gap: 12px; align-items: flex-start; background: #fff; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; }
.fact .icon { color: #ec4899; font-size: 1.6rem; flex: 0 0 auto; }
.fact .title { font-weight: 700; color: #0f172a; font-size: .9rem; }
When to use: features, benefits, or “did you know” facts that aren't numbers.
A top-N with bars
Combine a rank number, a label, and a bar to show an ordered leaderboard of values — most popular topics, top sellers, busiest days.
HTML
<div class="rank">
<div class="row">
<span class="pos">1</span><span class="name">CSS</span>
<span class="bar"><i style="width:100%"></i><b>1,240</b></span>
</div>
<div class="row">
<span class="pos">2</span><span class="name">HTML</span>
<span class="bar"><i style="width:82%"></i><b>1,010</b></span>
</div>
<div class="row">
<span class="pos">3</span><span class="name">JavaScript</span>
<span class="bar"><i style="width:64%"></i><b>790</b></span>
</div>
<div class="row">
<span class="pos">4</span><span class="name">Design</span>
<span class="bar"><i style="width:45%"></i><b>560</b></span>
</div>
</div>
.rank { display: grid; gap: 10px; max-width: 460px; }
.row { display: flex; align-items: center; gap: 12px; }
.pos { width: 26px; height: 26px; border-radius: 50%; background: #fce7f3; color: #be185d;
font-weight: 800; display: grid; place-items: center; font-size: .8rem; flex: 0 0 auto; }
.row:nth-child(1) .pos { background: #ec4899; color: #fff; }
.name { width: 84px; font-size: .82rem; color: #334155; font-weight: 600; flex: 0 0 auto; }
.bar { flex: 1; background: #fce7f3; border-radius: 8px; height: 26px; position: relative; overflow: hidden; }
.bar i { position: absolute; inset: 0 auto 0 0; background: #ec4899; border-radius: 8px; }
.bar b { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); font-size: .76rem; color: #831843; z-index: 1; }
When to use: “top 5” lists where both rank and magnitude matter.
Count with repeated icons
Instead of a bar, repeat an icon and fill in part of it — “7 in 10.” Pictographs make proportions feel human and concrete.
7 in 10 students study on their phone
HTML — filled vs. empty icons
<div class="picto">
<div class="row">
<span class="person on">👤</span><span class="person on">👤</span><span class="person on">👤</span><span class="person on">👤</span><span class="person on">👤</span><span class="person on">👤</span><span class="person on">👤</span><span class="person">👤</span><span class="person">👤</span><span class="person">👤</span>
</div>
<p class="cap"><b>7 in 10</b> students study on their phone</p>
</div>
.person { font-size: 1.7rem; color: #e5e7eb; } /* empty */
.person.on { color: #ec4899; } /* filled */
.cap { font-size: .85rem; color: #475569; margin-top: 8px; }
.cap b { color: #ec4899; }
When to use: “X out of Y” ratios about people or things — more relatable than a percentage alone.
A complete infographic poster
A real infographic combines these blocks into one story with a title, a few headline stats, a chart, and a takeaway. Here's a small poster built only from the pieces above.
How students learn web design
Takeaway: mobile-first design isn't optional.
Design tips: pick 2–3 colours and stick to them, keep one idea per block, guide the eye top-to-bottom, and always cite your source. Build each block with the snippets above, then stack them in a single column.
The whole infographic as one file
Every block above — big stat, stat grid, donut, comparison bars, process flow, timeline, ranked list, and pictograph — combined into one complete HTML file, arranged as a single-column infographic poster. Copy it into a new file called infographic.html, open it in a browser, and it just works — no libraries, no build step. Here's the live result, then the full code.
Live preview
Complete HTML — copy this whole file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2026 Learning Report — Infographic</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f6f7fb; color: #1f2433; line-height: 1.6; padding: 24px; }
.poster { max-width: 640px; margin: 0 auto; background: linear-gradient(160deg, #fff0f6, #fff);
border: 1px solid #fbcfe8; border-radius: 18px; padding: 32px 28px; }
/* header */
.ph { text-align: center; margin-bottom: 28px; }
.ph .k { font-size: .72rem; text-transform: uppercase; letter-spacing: .18em; color: #ec4899; font-weight: 800; }
.ph h1 { font-size: 1.7rem; color: #0f172a; margin-top: 4px; }
/* big stat */
.big-stat { text-align: center; margin-bottom: 28px; }
.big-stat .num { font-size: clamp(3rem, 12vw, 4.5rem); font-weight: 800; color: #ec4899; line-height: 1; letter-spacing: -.03em; }
.big-stat .label { font-size: 1rem; color: #475569; font-weight: 600; margin-top: 6px; }
.big-stat .sub { font-size: .82rem; color: #94a3b8; margin-top: 4px; }
/* stat grid */
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 16px; text-align: center; margin-bottom: 28px; }
.stat .icon { width: 48px; height: 48px; border-radius: 14px; display: grid; place-items: center; margin: 0 auto 8px; font-size: 1.4rem; color: #fff; }
.stat .num { font-size: 1.8rem; font-weight: 800; color: #0f172a; line-height: 1; }
.stat .lbl { font-size: .8rem; color: #64748b; font-weight: 600; margin-top: 4px; }
.block-title { font-size: .72rem; text-transform: uppercase; letter-spacing: .12em; color: #ec4899; font-weight: 800; margin-bottom: 12px; text-align: center; }
/* donuts */
.donuts { display: flex; gap: 22px; flex-wrap: wrap; justify-content: center; margin-bottom: 28px; }
.donut { width: 110px; height: 110px; border-radius: 50%; display: grid; place-items: center;
background: conic-gradient(var(--c) calc(var(--p) * 1%), #e5e7eb 0); }
.donut span { width: 80px; height: 80px; border-radius: 50%; background: #fff; display: grid; place-items: center; font-weight: 800; font-size: 1.2rem; color: #0f172a; }
.donut-cap { font-size: .8rem; color: #64748b; margin-top: 8px; text-align: center; }
/* comparison bars */
.bars { display: grid; gap: 12px; margin-bottom: 28px; }
.bar .top { display: flex; justify-content: space-between; font-size: .82rem; color: #334155; font-weight: 600; margin-bottom: 4px; }
.bar .track { background: #e5e7eb; border-radius: 999px; height: 18px; overflow: hidden; }
.bar .fill { height: 100%; border-radius: 999px; }
/* process flow */
.steps { display: flex; gap: 0; flex-wrap: wrap; margin-bottom: 28px; }
.step { flex: 1; min-width: 110px; text-align: center; position: relative; padding: 0 6px; }
.step .circle { width: 44px; height: 44px; border-radius: 50%; background: #ec4899; color: #fff; font-weight: 800; display: grid; place-items: center; margin: 0 auto 8px; position: relative; z-index: 1; }
.step:not(:last-child)::after { content: ""; position: absolute; top: 22px; left: 50%; width: 100%; height: 3px; background: #f9a8d4; z-index: 0; }
.step h4 { font-size: .9rem; color: #0f172a; margin-bottom: 2px; }
.step p { font-size: .76rem; color: #64748b; }
/* timeline */
.timeline { position: relative; padding-left: 28px; margin-bottom: 28px; }
.timeline::before { content: ""; position: absolute; left: 8px; top: 4px; bottom: 4px; width: 3px; background: #f9a8d4; }
.event { position: relative; margin-bottom: 14px; }
.event::before { content: ""; position: absolute; left: -24px; top: 3px; width: 13px; height: 13px; border-radius: 50%; background: #ec4899; border: 2px solid #fff; box-shadow: 0 0 0 2px #f9a8d4; }
.event .yr { font-weight: 800; color: #ec4899; font-size: .82rem; }
.event .t { color: #0f172a; font-weight: 700; font-size: .9rem; }
.event .d { color: #64748b; font-size: .8rem; }
/* ranked list */
.rank { display: grid; gap: 10px; margin-bottom: 28px; }
.row { display: flex; align-items: center; gap: 12px; }
.pos { width: 26px; height: 26px; border-radius: 50%; background: #fce7f3; color: #be185d; font-weight: 800; display: grid; place-items: center; font-size: .8rem; flex: 0 0 auto; }
.row:nth-child(1) .pos { background: #ec4899; color: #fff; }
.name { width: 84px; font-size: .82rem; color: #334155; font-weight: 600; flex: 0 0 auto; }
.rbar { flex: 1; background: #fce7f3; border-radius: 8px; height: 26px; position: relative; overflow: hidden; }
.rbar i { position: absolute; inset: 0 auto 0 0; background: #ec4899; border-radius: 8px; }
.rbar b { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); font-size: .76rem; color: #831843; z-index: 1; }
/* pictograph */
.picto { text-align: center; margin-bottom: 24px; }
.person { font-size: 1.7rem; color: #e5e7eb; }
.person.on { color: #ec4899; }
.cap { font-size: .85rem; color: #475569; margin-top: 8px; }
.cap b { color: #ec4899; }
.takeaway { text-align: center; font-size: .85rem; color: #64748b; padding-top: 20px; border-top: 1px dashed #fbcfe8; }
.takeaway b { color: #ec4899; }
</style>
</head>
<body>
<div class="poster">
<div class="ph">
<p class="k">2026 Report</p>
<h1>How students learn web design</h1>
</div>
<!-- big stat -->
<div class="big-stat">
<p class="num">73%</p>
<p class="label">of learners finish the course</p>
<p class="sub">based on 2,400 students · 2026</p>
</div>
<!-- stat grid -->
<div class="grid">
<div class="stat"><div class="icon" style="background:#ec4899;">👥</div><p class="num">12k</p><p class="lbl">Students</p></div>
<div class="stat"><div class="icon" style="background:#8b5cf6;">📖</div><p class="num">86</p><p class="lbl">Courses</p></div>
<div class="stat"><div class="icon" style="background:#0ea5e9;">🎓</div><p class="num">9.4k</p><p class="lbl">Certificates</p></div>
<div class="stat"><div class="icon" style="background:#22c55e;">⭐</div><p class="num">4.8</p><p class="lbl">Avg. rating</p></div>
</div>
<!-- donuts -->
<p class="block-title">Key proportions</p>
<div class="donuts">
<div><div class="donut" style="--p:73;--c:#ec4899;"><span>73%</span></div><p class="donut-cap">Completion</p></div>
<div><div class="donut" style="--p:48;--c:#8b5cf6;"><span>48%</span></div><p class="donut-cap">Mobile users</p></div>
<div><div class="donut" style="--p:91;--c:#22c55e;"><span>91%</span></div><p class="donut-cap">Satisfaction</p></div>
</div>
<!-- comparison bars -->
<p class="block-title">Where they watch</p>
<div class="bars">
<div class="bar"><div class="top"><span>Watch on mobile</span><span>70%</span></div><div class="track"><div class="fill" style="width:70%;background:#ec4899;"></div></div></div>
<div class="bar"><div class="top"><span>Watch on desktop</span><span>30%</span></div><div class="track"><div class="fill" style="width:30%;background:#8b5cf6;"></div></div></div>
</div>
<!-- process flow -->
<p class="block-title">How a course works</p>
<div class="steps">
<div class="step"><div class="circle">1</div><h4>Plan</h4><p>Pick a track</p></div>
<div class="step"><div class="circle">2</div><h4>Build</h4><p>Write code</p></div>
<div class="step"><div class="circle">3</div><h4>Test</h4><p>Check it</p></div>
<div class="step"><div class="circle">4</div><h4>Ship</h4><p>Go live</p></div>
</div>
<!-- timeline -->
<p class="block-title">Our story</p>
<div class="timeline">
<div class="event"><div class="yr">2023</div><div class="t">Idea</div><div class="d">The first sketch on a napkin.</div></div>
<div class="event"><div class="yr">2024</div><div class="t">Launch</div><div class="d">First version goes live.</div></div>
<div class="event"><div class="yr">2026</div><div class="t">Growth</div><div class="d">12,000 students and counting.</div></div>
</div>
<!-- ranked list -->
<p class="block-title">Most popular topics</p>
<div class="rank">
<div class="row"><span class="pos">1</span><span class="name">CSS</span><span class="rbar"><i style="width:100%;"></i><b>1,240</b></span></div>
<div class="row"><span class="pos">2</span><span class="name">HTML</span><span class="rbar"><i style="width:82%;"></i><b>1,010</b></span></div>
<div class="row"><span class="pos">3</span><span class="name">JavaScript</span><span class="rbar"><i style="width:64%;"></i><b>790</b></span></div>
<div class="row"><span class="pos">4</span><span class="name">Design</span><span class="rbar"><i style="width:45%;"></i><b>560</b></span></div>
</div>
<!-- pictograph -->
<div class="picto">
<div id="pictoRow"></div>
<p class="cap"><b>7 in 10</b> students study on their phone</p>
</div>
<p class="takeaway"><b>Takeaway:</b> mobile-first design isn't optional. · Source: 2026 Learning Report</p>
</div>
<script>
// build the pictograph: 7 filled people out of 10
var row = document.getElementById('pictoRow');
var html = '';
for (var i = 0; i < 10; i++) {
html += '<span class="person' + (i < 7 ? ' on' : '') + '">👤</span>';
}
row.innerHTML = html;
</script>
</body>
</html>
Keep building
See Data Patterns, Visual Design Patterns, and SVG Lab — or browse the full Component Library.