步骤条本质是导航控件,须用包裹,每步为,禁用.progress或div实现。

不能用 .progress 组件直接套步骤条——它只反映数值进度,不表达“当前在哪步”“哪些可点击”“是否校验通过”,硬套会导致键盘导航断裂、读屏器误读、表单逻辑错位。
用 nav + ol 搭语义化结构,别用 div 或 progress
步骤条本质是导航控件,不是度量仪表。必须用 <nav aria-label="表单步骤"></nav> 包裹 <ol class="nav nav-pills"></ol>,每步为 <li class="nav-item">@#@#@#@#@#@#@#@#@#@0</li>。
-
aria-current="step"是唯一被屏幕阅读器识别的“当前进行中”状态;class="active"对辅助技术不可见,也不参与状态绑定 - 每项
href必须指向对应表单区域 ID(如#step-2),否则浏览器前进/后退和锚点跳转失效 - 服务端渲染时,
aria-current必须由后端准确输出;否则 React/Vue hydrate 会错位,JS 补救无效 - 禁用未激活项时,用
tabindex="-1"+pointer-events: none,而不是disabled——后者会砍掉键盘焦点
图标用 ::before 伪元素生成,靠 aria-current 驱动样式
图标不能插 DOM(如 <i class="bi bi-check"></i>),否则小屏折行时基线错位、缩放偏移、语义污染。统一用 CSS 伪元素生成,样式由属性选择器控制。
- 基础圆点:
.nav-link::before { content: ""; display: inline-block; width: 1.25rem; height: 1.25rem; border-radius: 50%; margin-right: 0.5rem; vertical-align: middle; } - 当前步:
[aria-current="step"]::before { background-color: #0d6efd; } - 已完成:
[aria-current="true"]::before { content: "✓"; color: #198754; font-size: 0.875rem; }(注意:别混用"true"和"step") - 未开始:
:not([aria-current])::before { content: counter(step); }配合counter-reset: step;自增编号 - 移动端字体建议降到
0.875rem,防止nav-link高度撑开导致行距失衡
连线用 border-right + flex-grow: 1,别用 transform 或固定宽度
连接线必须随步骤推进动态延伸,且在小屏竖排时自动切换方向。伪元素 ::after 是最轻量、可控的方式。
- 横排时:
.nav-item:not(:last-child) .nav-link::after { border-right: 2px solid #e9ecef; flex-grow: 1; } - 竖排时(
@media (max-width: 576px)):.nav-link::after { border-right: none; border-bottom: 2px solid #e9ecef; } - 只在非末项画线,避免底部多一条线;别用
gap-3这类工具类——flex-column 下对齐不稳定 - 绝对定位或
transform: scaleX()易在断点错位,尤其文字折行后连线偏移
切换前必须同步校验,不能只改 UI 状态
用户点“下一步”若只更新 aria-current 或样式,会出现“进度走到第 3 步,但第 2 步邮箱根本没填”的逻辑断裂——后端收不到完整数据,前端后续逻辑可能崩溃。
- 在点击事件里调用
checkStepValidity(),而不是等最终submit时才校验 - 校验失败时,用
input.focus()定位到第一个无效字段,别只弹alert - 禁用“下一步”按钮直到当前步通过:
nextBtn.disabled = true,别只加opacity: 0.5 - 若某步含异步校验(如用户名可用性检查),按钮需进 loading 状态,并设
disabled防重复提交
最易被忽略的是:状态图标和连线必须由同一套 aria-current 值驱动,不能 JS 改一个属性、CSS 又监听另一个 class;服务端首次输出的 aria-current 若不准,客户端所有交互都会从根上错位。











