bootstrap 官方无内置步骤条组件,必须用语义化 nav+ol 结构、aria-current 属性标记状态、伪元素生成图标与连线,并同步表单校验、焦点管理及无障碍属性。
bootstrap 官方没有 .steps、.step-bar 或任何内置的步骤进度指示器组件,所谓“带状态图标的响应式步骤条”,必须用语义化结构(nav+ol)+ 自定义 css + 状态驱动逻辑实现。硬套 progress 或第三方封装,会破坏可访问性、键盘导航和状态同步。
用 nav + aria-current 搭语义化步骤结构
步骤条本质是导航控件,不是数值反馈器。必须用 <nav></nav> 包裹有序列表,每步用 <li class="nav-item">,链接用 <a class="nav-link"></a>,并靠 aria-current 属性标记状态:
-
aria-current="step"表示当前进行中(屏幕阅读器可读,且 Bootstrap 5+ 推荐) -
aria-current="true"或自定义data-status="completed"表示已完成(仅当需区分“完成”与“进行中”时) - 别用
class="active"—— 它对辅助技术不可见,也不参与状态绑定 - 每项
href应指向对应表单锚点(如#step-2),支持浏览器前进/后退
状态图标怎么加才不破布局
图标不能用绝对定位硬塞,否则小屏下易错位或重叠。推荐两种稳态方案:
- 用伪元素
::before统一生成圆点:.nav-link::before { content: ""; display: inline-block; width: 1.25rem; height: 1.25rem; border-radius: 50%; margin-right: 0.5rem; } - 状态样式由属性驱动:
[aria-current="step"]::before { background-color: #0d6efd; }、[aria-current="true"]::before { background-color: #198754; }、:not([aria-current])::before { background-color: #adb5bd; } - 图标尺寸用
rem,避免像素固定;文字折行时靠vertical-align: middle对齐基线 - 禁用未激活项时,用
tabindex="-1"+pointer-events: none,而不是disabled—— 后者会砍掉键盘焦点
响应式连线怎么画才不拉伸变形
连接线不是装饰,是进度指示的关键部分。伪元素 ::after 是最轻量、可控的方式:
- 只在非末项画线:
.nav-item:not(:last-child) .nav-link::after - 用
border-right+flex-grow: 1动态撑开,而非固定宽度或transform: scaleX() - 移动端竖排时,改用
border-bottom并重置padding和gap:@media (max-width: 576px) { .step-nav { flex-direction: column; gap: 1rem; } .nav-link::after { border-right: none; border-bottom: 2px solid #e9ecef; } } - 别依赖
gap-3这类工具类——在flex-column下它们的对齐逻辑不稳定
JS 切换状态时最容易漏掉的三件事
前端切换步骤常只改 UI,但真正可用的步骤条必须和表单校验强绑定:
- 点击“下一步”前,必须调用
checkStepValidity()校验当前字段;失败则focus()到首个无效输入,而不是弹 alert - 状态变更必须同步更新
aria-current属性值,并触发 DOM 重绘(React/Vue 需确保 hydrate 时服务端已输出正确属性) - 若某步被动态跳过(如根据用户选择隐藏第 3 步),连线宽度不能硬写
width: 33%,得用calc((100% - (N - 1) * gap) / N)动态计算
真正难的不是画出圆点或连线,而是让每一步的状态变化都和表单有效性、焦点管理、无障碍属性严格对齐。少一个环节,就等于给键盘用户或屏幕阅读器埋了个坑。











