aria-current 是唯一能正确驱动状态变化图标的属性,必须用 nav+ol 语义结构、href 锚点导航、CSS 伪元素生成图标、动态连线、tabindex="-1" 禁用未激活项,并绑定表单校验确保进度与数据一致。

aria-current 是唯一能正确驱动状态变化图标的属性,别用 class="active" 或 data-status 混搭——屏幕阅读器只认 aria-current="step" 和 aria-current="true",其他写法等于没标状态。
用 nav+ol 搭语义结构,不是 div 堆砌
步骤条是导航控件,不是装饰元素。必须用 <nav aria-label="表单步骤"> 包裹 <ol class="nav">,每步为 <li class="nav-item"><a href="#step-2" class="nav-link">账户设置</a></li>。href 必须指向对应锚点,否则浏览器前进/后退和键盘 Tab 导航会断。
常见错误:服务端渲染时漏传 aria-current,导致 React/Vue hydrate 后状态错位;或用 disabled 禁用未激活项,结果键盘焦点直接跳过整步。
图标用 ::before 伪元素生成,靠属性选择器切换
所有状态图标(圆点、对勾、数字)必须由 CSS 生成,不能插 <i> 或 SVG —— 否则小屏缩放时基线偏移、文字折行后图标错位。
关键样式规则:
.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-weight: bold; }(已完成,用字符比 SVG 更稳) -
:not([aria-current])::before { content: counter(step); counter-increment: step; }(未开始步自动编号)
移动端记得加 @media (max-width: 576px) { .nav-link::before { width: 1rem; height: 1rem; } },防图标撑高行距。
连线用 border-right+flex-grow,别碰 transform 或固定宽度
横排时连接线必须动态伸缩,否则断点切换后线条断裂或重叠。
正确写法:
- 只在非末项画线:
.nav-item:not(:last-child) .nav-link { border-right: 2px solid #e9ecef; flex-grow: 1; } - 确保父容器是
d-flex,且.nav-item设flex: 1或min-width: 0防文字撑宽 - 小屏竖排时切到
border-bottom:@media (max-width: 576px) { .nav-item:not(:last-child) .nav-link { border-right: none; border-bottom: 2px solid #e9ecef; margin-bottom: 1rem; } } - 禁用未激活项时,加
tabindex="-1"+pointer-events: none+opacity: 0.6,不砍键盘流
状态同步必须绑定表单校验,不能只改 UI
用户点“下一步”时,如果只更新 aria-current 而不校验字段,就会出现“进度走到第 3 步,但第 2 步邮箱为空”的逻辑断裂。
真实流程必须:
- 点击事件里调用
checkStepValidity(),逐字段检查input.checkValidity() - 校验失败时,
input.focus()定位到第一个无效项,不是弹alert - “下一步”按钮设
disabled = true直到当前步通过,不是仅加opacity - 含异步校验(如用户名可用性)时,按钮进
loading状态并设disabled防重复提交
最易被忽略的点:状态图标颜色和连线长度看似是样式问题,实则是可访问性和表单完整性的一体两面——aria-current 不准,图标就不可读;校验不同步,进度就是假象。


















