8pt

Progress Ring

环形进度•数字
介绍

纯 CSS 环形进度:两个半环用 rotate 拼出任意角度,中间数字同步递增。点击随机设定新目标。

纯 HTML、CSS 与少量原生 JS,没有框架依赖。复制提示词交给 Claude Code、Cursor、Trae 或 Codex,模型会把 Progress Ring 加进你的项目并换成你的配色。

适用场景

数据亮点、增长指标、计数器和统计卡片。

安装

订阅 Builder 后,用 8pt CLI 装进项目,或在已接入 8pt MCP 的编辑器里直接调用。

$ npm i -g @8pt-dev/cli && 8pt add progress-ring
mcp › 使用 8pt MCP 调用 get_component("progress-ring")

代码

Progress Ring 的源码,动效只用 transform 与 opacity,并尊重减少动态效果设置。

<div class="x-ring">
  <button type="button" class="x-ring__dial" aria-label="设置新进度">
    <span class="x-ring__half x-ring__half--r"><i></i></span>
    <span class="x-ring__half x-ring__half--l"><i></i></span>
    <span class="x-ring__face"><b>0</b><small>%</small></span>
  </button>
  <div class="x-ring__meta"><b>存储空间</b><span>已用 <em>0</em> / 100 GB</span></div>
</div>
.x-ring{display:flex;align-items:center;gap:20px;color:var(--d-fg,#fff)}
.x-ring__dial{--sz:132px;--th:12px;position:relative;width:var(--sz);height:var(--sz);padding:0;border:0;border-radius:50%;background:var(--d-line,rgba(255,255,255,.12));cursor:pointer;flex:none}
.x-ring__half{position:absolute;top:0;width:50%;height:100%;overflow:hidden}
.x-ring__half--r{left:50%}
.x-ring__half--l{left:0}
.x-ring__half i{position:absolute;top:0;width:200%;height:100%;border-radius:50%;transform:rotate(0);transition:transform .55s linear}
.x-ring__half--r i{left:-100%;background:linear-gradient(90deg,var(--d-accent,#4D74FF) 50%,transparent 50%)}
.x-ring__half--l i{left:0;background:linear-gradient(90deg,transparent 50%,color-mix(in srgb,var(--d-accent,#4D74FF) 70%,#9ef0ff) 50%)}
.x-ring__face{position:absolute;inset:var(--th);display:flex;align-items:center;justify-content:center;border-radius:50%;background:var(--d-bg,#09090d)}
.x-ring__face b{font:700 34px/1 var(--d-font,system-ui,sans-serif);letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.x-ring__face small{margin-left:2px;font:600 14px/1 var(--d-font,system-ui,sans-serif);color:var(--d-muted,#9b9ba8);transform:translateY(6px)}
.x-ring__meta{display:grid;gap:6px}
…
const init = (root) => {
  const dial = root.querySelector('.x-ring__dial'), r = dial.querySelector('.x-ring__half--r i'), l = dial.querySelector('.x-ring__half--l i');
  const num = dial.querySelector('b'), used = root.querySelector('.x-ring__meta em');
  let cur = 0, raf = 0, tl;
  const set = (p) => {
    const deg = p * 3.6, from = cur, fdeg = from * 3.6; cur = p;
    // right half sweeps 0-180deg, left half 180-360deg; when crossing 180 the halves run one after the other
    const rd = Math.min(deg, 180), ld = Math.max(deg - 180, 0);
    clearTimeout(tl); r.style.transitionDelay = l.style.transitionDelay = '0s';
    if (deg > 180 && fdeg < 180) { r.style.transform = `rotate(${rd}deg)`; l.style.transitionDelay = '.55s'; l.style.transform = `rotate(${ld}deg)`; }
    else if (deg < 180 && fdeg > 180) { l.style.transform = `rotate(${ld}deg)`; r.style.transitionDelay = '.55s'; r.style.transform = `rotate(${rd}deg)`; }
    else { r.style.transform = `rotate(${rd}deg)`; l.style.transform = `rotate(${ld}deg)`; }
…
订阅 Builder 查看完整源码。查看价格

更多数字组件

查看全部

Number Ticker

更多组件

查看全部

AI Prompt Composer

Film Strip Carousel

Auto Tab Showcase

Media Bento Grid

Agent Chat Window

Model Pill Marquee

Director Art Cards

Mac File Window

继续探索