bootstrap官方无.steps或.wizard内置组件,必须用+语义结构、aria-current="step"标记当前步、css伪元素生成图标与连线、js同步校验逻辑三者配合实现;禁用class="active",href须指向对应id锚点,小屏需媒体查询重置布局。

Bootstrap 官方没有 .steps、.wizard 或任何内置分步引导组件,所谓“表单分步引导教学”必须靠语义化 HTML + 属性驱动 CSS + 同步 JS 校验逻辑三者配合实现;硬套 .progress 或第三方插件会破坏键盘导航、读屏识别和状态一致性。
用 <nav></nav> + aria-current 搭语义化步骤结构
步骤条本质是导航控件,不是进度数值器。必须用 <nav aria-label="表单步骤"></nav> 包裹 <ol class="nav nav-pills"></ol>,每步为 <li class="nav-item">,链接用 <a></a> 并通过 aria-current 标记状态:
-
aria-current="step"表示当前进行中——这是唯一被屏幕阅读器识别、且 Bootstrap 5+ 推荐的方式;class="active"对辅助技术不可见,也不参与 SSR/hydrate 同步 - 每个
<a></a>的href必须指向对应表单区域 ID(如#step-2),否则浏览器前进/后退、锚点跳转、Tab 导航全部失效 - 服务端渲染时,
aria-current必须由后端准确输出;若用 React/Vue,hydration 阶段需严格对齐,否则焦点和读屏状态会错乱
图标和连线必须用伪元素 + 属性选择器生成
状态图标不能插额外 DOM 元素(比如在 <a></a> 里写 <i class="bi bi-check"></i>),否则小屏折行易错位、缩放后基线偏移、无障碍语义污染。统一用 ::before 生成:
-
.nav-link::before设固定尺寸圆点:width: 1.25rem; height: 1.25rem; border-radius: 50%; margin-right: 0.5rem; - 样式由属性驱动:
[aria-current="step"]::before设主色背景;[aria-current="true"]::before设完成图标(如content: "✓"; color: #198754;);:not([aria-current])::before设灰阶未激活色 - 连线用
.nav-item:not(:last-child) .nav-link::after+flex-grow: 1动态撑开,避免最后一项多画一条线;别用transform: scaleX()或内联style.width,容易卡顿或缩放中心偏移
切换前必须同步校验,不能只改 UI
用户点“下一步”时,如果只更新 aria-current 或加 CSS 类,就会出现“UI 走到第 3 步,但第 2 步邮箱字段为空”的逻辑断裂。真实流程必须在点击事件里触发校验:
- 调用
checkStepValidity()—— 不是等最终submit才校验,而是每步切换前立即执行 - 校验失败时,用
input.focus()定位到第一个无效字段,并配合scrollIntoView({ behavior: 'smooth', block: 'center' })防止被软键盘遮挡 - 禁用“下一步”按钮:
nextBtn.disabled = true,而不是只加opacity: 0.5;否则用户仍可点击、触屏仍可激活 - 含异步校验(如用户名唯一性检查)时,按钮需进 loading 状态,并设
disabled防重复提交
iOS Safari 的实时验证必须手动控制 is-invalid 类
iOS Safari 对 :invalid 伪类触发极其保守,blur 后可能不响应,input 过程中几乎不触发,导致 is-invalid 类加不上、.invalid-feedback 不显示。必须用 JS 主动控制:
- 监听
blur和input(仅对邮箱、手机号等强格式字段),手动调用input.checkValidity() - 根据结果显式
classList.add('is-invalid')或remove('is-invalid'),并设置.invalid-feedback.textContent -
<input>和<div class="invalid-feedback"> 必须同级、无间隔标签(包括空格和注释);若用 <code>form-floating,反馈元素仍需紧跟<input> - 整个
<form></form>必须有novalidate属性,否则浏览器原生弹窗会拦截并阻止 Bootstrap 样式激活
最容易被忽略的是:服务端输出的 aria-current 和前端 JS 切换逻辑必须严格对齐,否则 hydrate 错位会导致焦点丢失、读屏误读、校验跳步——这不是样式问题,是 DOM 与逻辑状态的耦合断裂。











