Bootstrap响应式分步进度指示器状态控制与图标切换实现

作者:技术拾光时间:2026-08-12 08:01:33浏览:497

在 Bootstrap 的响应式分步进度指示器中,aria-current 是唯一合法的状态标记方式,必须使用 aria-current="step" 标识当前步骤,使用 aria-current="true" 标识已完成步骤,禁止使用 class="active"。图标应统一通过 ::before

在 Bootstrap 的响应式分步进度指示器中,aria-current 是唯一合法的状态标记方式,必须使用 aria-current="step" 标识当前步骤,使用 aria-current="true" 标识已完成步骤,禁止使用 class="active"。图标应统一通过 ::before 伪元素生成,连接线则通过 border 配合 flex-grow 实现;在切换步骤之前,还必须同步校验表单有效性。

Bootstrap响应式分步进度指示器状态控制与图标切换实现

aria-current 是唯一合法的状态标记方式

Bootstrap 最新版本并未内置 .steps、.step-bar 这类现成的分步组件,因此这类状态切换本质上应由 HTML 属性驱动,不能仅依赖 class 名称实现。虽然使用 class="active" 或 class="completed" 看起来更直接,但这些状态无法被屏幕阅读器识别,也不利于 SSR 与 hydrate 过程中的状态同步,在 React、Vue 等服务端渲染场景下尤其容易出现不一致问题。此外,用户使用 Tab 键导航时,焦点还有可能跳过未激活的步骤项。

更合适的做法是使用 aria-current="step" 标记当前正在进行的步骤,这是读屏软件能够明确识别的值;而 aria-current="true" 则用于表示该步骤已经完成,但仅适用于确实需要区分“已完成”与“进行中”的场景。两者不能混用。服务端输出这些属性时必须准确无误,前端通过 JS 切换状态时,也必须同步更新对应属性,不能只修改 class。

  • 每个步骤链接都必须使用 标签,且 href 要指向对应的表单区域 ID,例如 #step-2,否则浏览器的前进、后退与锚点跳转功能将失效
  • 如果需要禁用未激活项,应使用 tabindex="-1" 配合 pointer-events: none,不要使用 disabled,因为后者会直接移除键盘焦点能力
  • 在 JS 中不要通过 element.classList.add("active") 控制状态,CSS 应基于 [aria-current="step"] { ... } 这类属性选择器编写

图标必须用 ::before 伪元素生成,且尺寸用 rem

如果直接插入 ● 或通过绝对定位添加图标,在小屏环境下文字换行后,图标很容易出现错位、重叠或悬空的问题。因此,所有状态图标,包括圆点、对勾和数字,都应统一由 ::before 伪元素生成,并通过 aria-current 属性控制样式变化。

关键 CSS 示例:

.na v-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 { background-color: #198754; }
:not([aria-current])::before { background-color: #adb5bd; }
  • 尺寸应使用 rem 而不是 px,以保证在缩放和响应式场景下比例保持一致
  • 必须添加 vertical-align: middle,否则基线不一致会导致图标上浮或下沉
  • 移动端字体建议调整为 font-size: 0.875rem,避免 na v-link 高度被撑开后造成行距失衡

连线必须用 border-right + flex-grow,禁用 transform 和固定 width

所谓进度延伸,本质上是让连接线随着步骤推进自动填充剩余空间。如果使用 transform: scaleX() 或内联 style.width 控制长度,容易引发动画卡顿、缩放中心偏移和断点错位等问题,尤其在文字换行后,连接线常常会超出容器或发生断裂。

横向排列时的标准写法如下:

.na v-item:not(:last-child) .na v-link {
border-right: 2px solid #e9ecef;
flex-grow: 1;
}

在竖向排列场景下,即 @media (max-width: 576px) 时,可切换为:

.na v-link {
border-bottom: 2px solid #e9ecef;
margin-bottom: 1rem;
}
  • 连接线只应绘制在非末项上,:not(:last-child) 是关键,否则最后一项底部或尾部会多出一条线
  • 不要依赖 gap-3 这类工具类控制间距,因为它们在 flex column 布局下表现并不稳定,应在媒体查询中明确重置 gap 和 padding
  • 使用绝对定位或 ::after 绘制连接线时,在小屏幕下很容易发生偏移,尤其是步骤标题换行之后

切换前必须校验,不能只改 UI

当用户点击“下一步”时,如果只是更新 aria-current 和视觉样式,而没有同步校验当前步骤内容,就会出现界面已经进入第 3 步,但第 2 步中的邮箱字段仍为空的逻辑断层。这不仅可能导致后端接收到不完整数据,还可能在后续流程中触发 JS 报错。

  • 在点击事件中必须调用 checkStepValidity(),不能等到最终 submit 时再统一校验
  • 校验失败时,应通过 input.focus() 将焦点定位到第一个无效字段,而不是只弹出 alert
  • “下一步”按钮应设置为 nextBtn.disabled = true,直到当前步骤验证通过,不能仅通过 opacity: 0.5 模拟不可用状态
  • 如果包含异步校验,例如用户名可用性检查,按钮还应进入 loading 状态并设置 disabled,以避免重复提交

实际难点并不在于绘制连接线或切换图标,而在于状态同步。aria-current、表单有效性、焦点位置和按钮禁用状态这四个部分必须原子化更新,任何一个环节遗漏,都会影响可访问性与业务逻辑的完整性。