步骤进度条(Stepper 分步表单进度组件动画源码)

CSSJS 许可:自研原创

步骤进度条源码:四步 Stepper 状态机,连线按百分比填充、圆点弹性放大并打勾、当前步呼吸高亮,上一步/下一步按钮联动禁用,原生 JS 零依赖,适合结算流程。

效果演示(真实可交互)

多步骤流程(注册、结算、问卷)最怕用户迷失,步骤进度条就是导航锚点。演示区模拟了一个四步流程:填写信息 → 确认订单 → 在线支付 → 完成。点击「下一步」,底部连接线以蓝绿色渐变从左向右填充对应百分比,当前步骤的圆点放大并泛起呼吸光环,已完成的圆点变为实心渐变并弹出 ✓;当前步名称同步更新,「上一步 / 下一步」按钮在首尾两端自动禁用,最后一步按钮变为「已完成 ✓」。整个流程是一个完整的状态机,接入真实业务时只需替换步骤名称数组与每步的表单内容。状态机的核心是单一数据源:当前步骤只存在 cur 变量里,渲染函数根据它一次性刷新圆点、连线、文案与按钮状态,不会出现多处状态不同步的问题。步数名称数组独立维护,换业务只需改 NAMES。分步流程中「回到上一步」同样重要:回退时已完成步骤的 ✓ 会保留,只有当前步状态变化,用户始终清楚自己走到哪、修改过什么,二次确认环节也不会被跳过。

1 填写信息
2 确认订单
3 在线支付
4 完成

当前第 1 步:填写信息

完整代码

HTML:步骤列表 + 状态文字 + 控制按钮,当前步骤存为 data-cur:

<div class="ps-steps" id="psSteps" data-cur="1">
  <div class="ps-step ps-active" data-step="1">
    <span class="ps-dot">1</span><span class="ps-name">填写信息</span>
  </div>
  <div class="ps-step" data-step="2">
    <span class="ps-dot">2</span><span class="ps-name">确认订单</span>
  </div>
  <div class="ps-step" data-step="3">
    <span class="ps-dot">3</span><span class="ps-name">在线支付</span>
  </div>
  <div class="ps-step" data-step="4">
    <span class="ps-dot">4</span><span class="ps-name">完成</span>
  </div>
</div>
<p class="ps-status" id="psStatus">当前第 1 步:填写信息</p>
<button id="psPrev">← 上一步</button>
<button id="psNext">下一步 →</button>

CSS:连接线用容器的 ::before(底槽)与 ::after(进度)双伪元素,宽度按步骤百分比切换:

.ps-steps { position: relative; display: flex; justify-content: space-between; }
.ps-steps::before {   /* 底槽 */
  content: ""; position: absolute; top: 19px; left: 10%; right: 10%; height: 3px;
  background: #e4e8f5; border-radius: 3px;
}
.ps-steps::after {    /* 进度填充 */
  content: ""; position: absolute; top: 19px; left: 10%; height: 3px; width: 0;
  background: linear-gradient(90deg, #6c8cff, #34c7a1);
  transition: width .5s cubic-bezier(.4, 0, .2, 1);
}
.ps-steps[data-cur="2"]::after { width: 26.6%; }   /* 四步均匀分布:80% / 3 */
.ps-steps[data-cur="3"]::after { width: 53.3%; }
.ps-steps[data-cur="4"]::after { width: 80%; }

圆点三态:当前步放大呼吸、完成步打勾弹入:

.ps-dot { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  background: #fff; border: 2px solid #d4daea; color: #8892ab; font-weight: 700;
  transition: background .4s ease, border-color .4s ease, color .4s ease, transform .4s cubic-bezier(.34,1.4,.64,1); }

.ps-step.ps-active .ps-dot { border-color: #6c8cff; color: #6c8cff; transform: scale(1.15);
  box-shadow: 0 0 0 7px rgba(108,140,255,.15); animation: ps-pulse 1.6s ease-in-out infinite; }
@keyframes ps-pulse { 50% { box-shadow: 0 0 0 12px rgba(108,140,255,.06); } }

.ps-step.ps-done .ps-dot { background: linear-gradient(135deg, #6c8cff, #34c7a1);
  border-color: transparent; color: #fff; font-size: 0; }
.ps-step.ps-done .ps-dot::after { content: "✓"; font-size: 16px; animation: ps-check .45s cubic-bezier(.34,1.6,.64,1); }
@keyframes ps-check { from { transform: scale(.3) rotate(-20deg); opacity: 0; } }

原生 JS:状态机 + 按钮联动:

const stepsBox = document.getElementById('psSteps');
const status = document.getElementById('psStatus');
const prevBtn = document.getElementById('psPrev');
const nextBtn = document.getElementById('psNext');
const NAMES = ['填写信息', '确认订单', '在线支付', '完成'];
let cur = 1;

function render() {
  stepsBox.dataset.cur = cur;
  stepsBox.querySelectorAll('.ps-step').forEach((step) => {
    const n = Number(step.dataset.step);
    step.classList.toggle('ps-done', n < cur);
    step.classList.toggle('ps-active', n === cur);
  });
  status.textContent = `当前第 ${cur} 步:${NAMES[cur - 1]}`;
  prevBtn.disabled = cur === 1;
  nextBtn.disabled = cur === 4;
  nextBtn.textContent = cur === 4 ? '已完成 ✓' : '下一步 →';
}
nextBtn.addEventListener('click', () => { if (cur < 4) { cur++; render(); } });
prevBtn.addEventListener('click', () => { if (cur > 1) { cur--; render(); } });
render();

参数说明

参数默认值说明
步骤数4增减步骤时同步调整 ::after 的宽度档位
进度档位26.6% / 53.3% / 80%公式:80% × (cur-1) / (n-1),左右各留 10%
填充时长transition: width .5s300-600ms,过长会显得拖沓
呼吸动画ps-pulse 1.6s当前步持续高亮,明确「你在这里」
完成打勾ps-check .45s过冲系数 1.6,✓ 弹出更俏皮

兼容性与性能

常见问题

Q: 进度条宽度和步骤对不齐? 宽度档位必须按公式 80% × (cur-1) / (n-1) 重算:四步时为 0 / 26.6 / 53.3 / 80%,改步骤数就要改所有档位,否则线头对不上圆点。

Q: 想支持点击步骤跳转? 给每个 .ps-step 加 click 监听并校验「只能回到已完成的步骤」,在 render() 里把可跳转步骤的圆点设为 cursor: pointer。

Q: 步骤很多(6 步以上)放不下? 缩小圆点与字号、允许 .ps-name 省略号截断,或改成横向滚动容器;连接线百分比公式不变。

Q: 可以商用吗? 可以。本组件为粤喵自研原创代码,免费商用无需署名。

许可与来源

  • 许可证:自研原创 —— 粤喵自研原创,可免费用于个人与商业项目,无需署名。查看来源公示与许可清单
  • 来源:粤喵团队原创自研(从效果思路到代码实现均为独立完成,未直接复制第三方代码)
  • 首次发布:2026-09-01 · 最近更新:2026-09-01
  • 修改日志:2026-09-01 首次发布;2026-09-13 补充许可证与来源标注、复制按钮说明与法务页入口
  • 纠错:联系页面 / min@cactus.asia,2 个工作日内核实处理

常见问题

这个组件可以商用吗?

可以。本组件为粤喵自研原创,可免费用于个人和商业项目,无需署名。

浏览器兼容性如何?

支持所有现代浏览器(Chrome / Firefox / Safari / Edge 最新版本)。旧版 IE 不支持 CSS 动画相关特性。

怎么修改动画参数?

直接调整 CSS 中的 animation-duration(时长)、animation-timing-function(缓动曲线)等属性即可,代码中有注释说明。

✍️ 作者与审核