22 CSS Transition Effects 22 / 22

Progress Bar Animation

Labelled skill bars, shimmer and striped variants, thin page-load indicators, circular SVG rings and step segment indicators with animated fills.

CSS + JS MIT licensed
Live Demo Open in tab

This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.

Open in playground

The code

<div class="page">
  <h1>Progress Bar Animation CSS</h1>
  <p class="subtitle">Smooth fills, shimmer, radial rings and step indicators</p>

  <!-- 1. Standard -->
  <section>
    <h2>Skill / Label Bars</h2>
    <button class="replay-btn" onclick="runBars()">↺ Replay</button>
    <div class="bar-list" id="barList">
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">TypeScript</span><span class="bar-pct" id="pct0">0%</span></div><div class="bar-track"><div class="bar-fill bf-blue"  data-to="92"></div></div></div>
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">React</span><span class="bar-pct" id="pct1">0%</span></div><div class="bar-track"><div class="bar-fill bf-blue"  data-to="88"></div></div></div>
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">Node.js</span><span class="bar-pct" id="pct2">0%</span></div><div class="bar-track"><div class="bar-fill bf-green" data-to="79"></div></div></div>
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">PostgreSQL</span><span class="bar-pct" id="pct3">0%</span></div><div class="bar-track"><div class="bar-fill bf-purple" data-to="70"></div></div></div>
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">Rust</span><span class="bar-pct" id="pct4">0%</span></div><div class="bar-track"><div class="bar-fill bf-orange" data-to="45"></div></div></div>
    </div>
  </section>

  <!-- 2. Shimmer / stripe -->
  <section>
    <h2>Shimmer & Striped Variants</h2>
    <div class="bar-list" id="barList2">
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">Upload progress</span><span class="bar-pct" id="pct5">0%</span></div><div class="bar-track" style="height:12px"><div class="bar-fill bf-blue shimmer" data-to="67"></div></div></div>
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">Installing packages</span><span class="bar-pct" id="pct6">0%</span></div><div class="bar-track" style="height:12px;background:#1e3a2f"><div class="bar-fill bf-green striped" data-to="55"></div></div></div>
      <div class="bar-row"><div class="bar-meta"><span class="bar-label">Syncing data</span><span class="bar-pct" id="pct7">0%</span></div><div class="bar-track" style="height:12px"><div class="bar-fill bf-purple" data-to="83"></div></div></div>
    </div>
  </section>

  <!-- 3. Thin loaders -->
  <section>
    <h2>Page / Loading Indicators</h2>
    <div class="loader-box">
      <div class="loader-label">Determinate — fetching data</div>
      <div class="loader-track"><div class="loader-fill pulse-glow" id="thinLoader"></div></div>
    </div>
    <div class="loader-box">
      <div class="loader-label">Indeterminate — waiting for server</div>
      <div class="loader-track"><div class="loader-fill indeterminate"></div></div>
    </div>
  </section>

  <!-- 4. Circular -->
  <section>
    <h2>Circular Progress Rings</h2>
    <button class="replay-btn" onclick="runCircles()">↺ Replay</button>
    <div class="circle-grid" id="circleGrid">
      <svg width="0" height="0"><defs><linearGradient id="grad-blue" x1="0" y1="0" x2="1" y2="0"><stop offset="0%" stop-color="#1d6fe6"/><stop offset="100%" stop-color="#58a6ff"/></linearGradient></defs></svg>
    </div>
  </section>

  <!-- 5. Steps -->
  <section>
    <h2>Step Indicators</h2>
    <button class="replay-btn" onclick="runSteps()">↺ Replay</button>
    <div id="stepWrap">
      <div style="margin-bottom:16px">
        <div class="bar-meta" style="margin-bottom:8px"><span class="bar-label">Order progress</span><span class="bar-pct" id="stepLabel">Step 3 of 5</span></div>
        <div class="step-track" id="stepTrack"></div>
        <div class="step-labels"><span>Placed</span><span>Confirmed</span><span>Packed</span><span>Shipped</span><span>Delivered</span></div>
      </div>
    </div>
  </section>
</div>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', sans-serif; background: #0d1117; color: #e6edf3; min-height: 100vh; }

.page { padding: 60px 40px; max-width: 900px; margin: 0 auto; }
h1 { font-size: 2rem; text-align: center; margin-bottom: 8px; color: #fff; }
.subtitle { color: #8b949e; text-align: center; margin-bottom: 50px; }
section { margin-bottom: 60px; }
section > h2 { color: #58a6ff; font-size: .75rem; text-transform: uppercase; letter-spacing: 3px; margin-bottom: 20px; padding-bottom: 8px; border-bottom: 1px solid #21262d; }

.replay-btn {
  display: inline-flex; gap: 6px; align-items: center; margin-bottom: 20px;
  padding: 8px 18px; border-radius: 8px; border: 1px solid #30363d;
  background: #161b22; color: #c9d1d9; font-size: .82rem; cursor: pointer;
  transition: background .2s;
}
.replay-btn:hover { background: #21262d; }

/* ─────────────────────────────────────
   1. Standard labelled bars
───────────────────────────────────── */
.bar-list { display: flex; flex-direction: column; gap: 18px; }
.bar-row { }
.bar-meta { display: flex; justify-content: space-between; margin-bottom: 8px; }
.bar-label { font-size: .875rem; color: #e6edf3; }
.bar-pct   { font-size: .875rem; color: #8b949e; font-variant-numeric: tabular-nums; }
.bar-track {
  height: 8px; border-radius: 4px;
  background: #21262d; overflow: hidden;
}
.bar-fill {
  height: 100%; border-radius: 4px; width: 0;
  transition: width 1.2s cubic-bezier(.25,1,.5,1);
}
.bf-blue   { background: linear-gradient(90deg, #1d6fe6, #58a6ff); }
.bf-green  { background: linear-gradient(90deg, #1a7f37, #3fb950); }
.bf-purple { background: linear-gradient(90deg, #5e2d91, #a78bfa); }
.bf-orange { background: linear-gradient(90deg, #9a4f00, #f0883e); }
.bf-red    { background: linear-gradient(90deg, #8a1f1f, #f85149); }

/* ─────────────────────────────────────
   2. Striped / animated shimmer bars
───────────────────────────────────── */
.bar-fill.striped {
  background-image: repeating-linear-gradient(
    45deg,
    rgba(255,255,255,.08) 0,
    rgba(255,255,255,.08) 10px,
    transparent 10px,
    transparent 20px
  );
  background-size: 28px 100%;
  animation: stripe-move 1s linear infinite;
}
@keyframes stripe-move {
  from { background-position: 0 0; }
  to   { background-position: 28px 0; }
}
.bar-fill.shimmer::after {
  content: ''; display: block; height: 100%;
  background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,.25) 50%, transparent 100%);
  background-size: 60% 100%; background-repeat: no-repeat;
  animation: shimmer-sweep 2s ease-in-out infinite;
}
@keyframes shimmer-sweep {
  from { background-position: -60% 0; }
  to   { background-position: 160% 0; }
}

/* ─────────────────────────────────────
   3. Thin loader / page-top bars
───────────────────────────────────── */
.loader-box { background: #161b22; border-radius: 12px; padding: 24px; margin-bottom: 12px; }
.loader-label { color: #8b949e; font-size: .8rem; margin-bottom: 12px; }
.loader-track { height: 3px; background: #21262d; border-radius: 2px; overflow: hidden; }
.loader-fill {
  height: 100%; border-radius: 2px;
  background: linear-gradient(90deg, #58a6ff, #a78bfa);
}
.loader-fill.indeterminate {
  width: 40%; animation: indeterminate 1.8s ease-in-out infinite;
}
@keyframes indeterminate {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}
.loader-fill.pulse-glow {
  width: 0; transition: width 2s ease;
  box-shadow: 0 0 8px rgba(88,166,255,.7);
}

/* ─────────────────────────────────────
   4. Circular / radial
───────────────────────────────────── */
.circle-grid { display: flex; flex-wrap: wrap; gap: 24px; }
.circle-wrap { text-align: center; }
.circle-svg { transform: rotate(-90deg); }
.circle-track { fill: none; stroke: #21262d; stroke-width: 6; }
.circle-arc {
  fill: none; stroke-width: 6; stroke-linecap: round;
  stroke-dashoffset: 283; /* full circumference = 2π×45 ≈ 283 */
  transition: stroke-dashoffset 1.4s cubic-bezier(.25,1,.5,1);
}
.ca-blue   { stroke: url(#grad-blue); }
.ca-green  { stroke: #3fb950; }
.ca-purple { stroke: #a78bfa; }
.ca-orange { stroke: #f0883e; }
.circle-inner {
  font-size: 1.1rem; font-weight: 700; color: #fff; margin-top: 8px;
}
.circle-sub { font-size: .75rem; color: #8b949e; }

/* ─────────────────────────────────────
   5. Step / multi-segment
───────────────────────────────────── */
.step-track { display: flex; height: 10px; border-radius: 5px; overflow: hidden; gap: 2px; }
.step-seg { flex: 1; background: #21262d; border-radius: 3px; transform-origin: left; transform: scaleX(0); transition: transform .4s ease; }
.step-seg.filled { background: #3fb950; }
.step-seg.done   { transform: scaleX(1); }

.step-labels { display: flex; justify-content: space-between; margin-top: 8px; }
.step-labels span { font-size: .72rem; color: #8b949e; }
/* ── Animate % counter ── */
  function animatePct(el, to, dur = 1200) {
    let start = null;
    function step(ts) {
      if (!start) start = ts;
      const p = Math.min((ts - start) / dur, 1);
      el.textContent = Math.round(p * to) + '%';
      if (p < 1) requestAnimationFrame(step);
    }
    requestAnimationFrame(step);
  }

  /* ── 1 & 2. Linear bars ── */
  function runBars() {
    ['barList','barList2'].forEach(id => {
      document.querySelectorAll(`#${id} .bar-fill`).forEach((fill, i) => {
        fill.style.width = '0';
        void fill.offsetWidth;
        const to = fill.dataset.to;
        setTimeout(() => {
          fill.style.width = to + '%';
          const pctEl = document.getElementById('pct' + (id === 'barList' ? i : i + 5));
          if (pctEl) animatePct(pctEl, parseInt(to));
        }, i * 150);
      });
    });
    // Thin loader
    const tl = document.getElementById('thinLoader');
    tl.style.width = '0';
    void tl.offsetWidth;
    setTimeout(() => { tl.style.width = '78%'; }, 300);
  }

  /* ── 4. Circular ── */
  const CIRCLES = [
    { pct: 87, color: 'ca-blue',   label: 'Performance', stroke: 'url(#grad-blue)' },
    { pct: 73, color: 'ca-green',  label: 'Accessibility', stroke: '#3fb950' },
    { pct: 94, color: 'ca-purple', label: 'Best Practice', stroke: '#a78bfa' },
    { pct: 61, color: 'ca-orange', label: 'SEO Score',    stroke: '#f0883e' },
  ];
  const C = 2 * Math.PI * 45; // ≈ 282.7

  function buildCircles() {
    const grid = document.getElementById('circleGrid');
    // keep the defs svg
    const defs = grid.querySelector('svg');
    grid.innerHTML = '';
    grid.appendChild(defs);
    CIRCLES.forEach(d => {
      const wrap = document.createElement('div');
      wrap.className = 'circle-wrap';
      wrap.innerHTML = `
        <svg class="circle-svg" width="100" height="100" viewBox="0 0 100 100">
          <circle class="circle-track" cx="50" cy="50" r="45"/>
          <circle class="circle-arc ${d.color}" cx="50" cy="50" r="45"
            stroke-dasharray="${C}" stroke-dashoffset="${C}"/>
        </svg>
        <div class="circle-inner">0%</div>
        <div class="circle-sub">${d.label}</div>`;
      grid.appendChild(wrap);
    });
  }

  function runCircles() {
    buildCircles();
    CIRCLES.forEach((d, i) => {
      const arcs = document.querySelectorAll('.circle-arc');
      const nums = document.querySelectorAll('.circle-inner');
      setTimeout(() => {
        arcs[i].style.strokeDashoffset = C * (1 - d.pct / 100);
        animatePct(nums[i], d.pct, 1400);
      }, i * 180);
    });
  }

  /* ── 5. Steps ── */
  const TOTAL_STEPS = 5, FILLED = 3;
  function buildSteps() {
    const track = document.getElementById('stepTrack');
    track.innerHTML = '';
    for (let i = 0; i < TOTAL_STEPS; i++) {
      const seg = document.createElement('div');
      seg.className = 'step-seg' + (i < FILLED ? ' filled' : '');
      track.appendChild(seg);
    }
  }
  function runSteps() {
    buildSteps();
    document.querySelectorAll('.step-seg').forEach((seg, i) => {
      setTimeout(() => seg.classList.add('done'), i * 150 + 100);
    });
  }

  // Init
  setTimeout(runBars, 300);
  setTimeout(runCircles, 500);
  setTimeout(runSteps, 700);

Search CodeFronts

Loading…