bootstrap官方无内置分步表单组件,必须用语义化+结构、aria-current="step"标记当前步、js同步校验逻辑三者配合实现;禁用class="active",href须指向对应id锚点,小屏竖排需媒体查询重置border-bottom与gap。

Bootstrap 官方没有内置分步表单组件,所谓“带验证状态的响应式分步表单”,必须用语义化 <nav></nav> + <ol></ol> 结构、aria-current 驱动状态、JS 同步校验逻辑三者配合实现。只改样式不校验,或硬套 .progress,会导致表单跳步、无障碍失效、服务端与前端状态错位。
怎么搭语义化结构并标记当前步
步骤条本质是导航控件,不是进度数值器。必须用 <nav aria-label="表单步骤"></nav> 包裹有序列表,每步为 <li class="nav-item">,链接用 <a class="nav-link"></a>,并通过 aria-current 属性声明状态:
-
aria-current="step"表示当前进行中——这是唯一被屏幕阅读器识别、且 Bootstrap 5+ 推荐的方式;class="active"对辅助技术不可见,也不参与 SSR/hydrate 同步 -
href必须指向对应表单区域 ID(如#step-2),否则浏览器前进/后退、锚点跳转、键盘 Tab 导航都会失效 - 服务端渲染时,
aria-current必须由后端准确输出;若用 React/Vue,hydration 阶段需严格对齐,否则焦点和读屏状态会错乱
切换前必须同步执行校验,不能只改 UI
用户点“下一步”时,如果只更新 aria-current 或加 CSS 类,就会出现“UI 走到第 3 步,但第 2 步邮箱字段为空”的逻辑断裂。真实流程必须在点击事件里触发校验:
- 调用
checkStepValidity()—— 不是等最终submit才校验,而是每步切换前立即执行 - 校验失败时,用
input.focus()定位到第一个无效字段,别只弹alert或仅高亮样式 - 禁用“下一步”按钮:设
nextBtn.disabled = true,而不是只加opacity: 0.5;否则用户仍可点击、触屏仍可激活 - 含异步校验(如用户名唯一性检查)时,按钮需进 loading 状态,并设
disabled防重复提交
验证状态怎么映射到 UI 元素上
状态样式必须由属性驱动,不能靠 JS 动态加 class,否则读屏器无法感知,CSS 也无法响应变化:
- 当前步:
[aria-current="step"] .nav-link::before { background-color: #0d6efd; } - 已完成步:
[aria-current="true"] .nav-link::before { background-color: #198754; }(注意别混用"true"和"step") - 未激活步:
:not([aria-current]) .nav-link::before { background-color: #adb5bd; } - 禁用未激活项时,用
tabindex="-1"+pointer-events: none;别用disabled—— 它会砍掉键盘焦点,破坏 Tab 导航流
小屏竖排时连线和间距怎么稳住不崩
横排时用 flex-grow: 1 + border-right 画连接线,小屏一竖排就容易拉伸变形、图标错位、文字折行撑开高度。关键要分层控制:
- 竖排时改用
border-bottom,并在媒体查询里重置:@media (max-width: 576px) { .nav-link { border-bottom: 2px solid #e9ecef; margin-bottom: 1rem; } } - 字体大小降到
0.875rem,防止nav-link高度突变导致行距失衡 - gap 值别依赖
gap-4这类工具类——它在flex-column下行为不稳定;直接写gap: 1.5rem - align-items 默认是
center,竖排时会让文字随图标高度浮动偏移,必须覆盖为align-items: flex-start
真正难的不是画出连线或圆点,而是让每一步的校验、焦点、状态、无障碍属性全部同步。一个没处理好的 aria-current 输出,或一次漏掉的 focus() 调用,就会让整个流程在读屏器下不可用,或在移动端失去焦点控制。











