Bootstrap原生可实现垂直响应式步骤条:用nav+flex-column构建语义结构,aria-current驱动状态,tabindex="-1"+pointer-events:none禁用未激活步,进度条嵌入每步内部并重置小屏gap/padding/align-items。
直接用 bootstrap 原生类就能做,但必须放弃“一步封装”的幻想——垂直 + 进度 + 响应式三者叠加时,nav + flex-column + progress 分层控制最稳,硬套 list-group 或 js 组件反而容易在小屏断行错位、进度条塌陷、焦点丢失。
用 nav + flex-column 实现语义化垂直结构
Bootstrap 没有内置 steps 组件,但 nav 天然支持步骤语义:nav-item 表示每一步,nav-link 承载标题与状态,aria-current 驱动可访问性。垂直布局靠 flex-column,不是靠 position: absolute 或 float。
- 大屏默认横排?加
flex-md-row;小屏强制竖排?只写flex-column即可(Bootstrap 5+ 默认移动端 flex-column) - 别用
.disabled禁用未激活步——它会砍掉键盘焦点;改用tabindex="-1"+pointer-events: none - 每步之间画竖线?用
border-left+ps-3(左 padding),比伪元素::before更稳,不依赖父容器高度 - 移动端字体过大导致行高撑开?加
fs-sm或自定义font-size: 0.875rem在@media (max-width: 576px)里
把 progress 嵌进每步内部,而不是单独一行
常见错误是把 .progress 放在 nav 外面,结果小屏下进度条被截断、文字重叠。正确做法是:每个 nav-item 内部包含标题、描述、进度条三部分,用 flex-column gap-2 控制间距。
-
<div class="progress"><div class="progress-bar" style="width: 40%"></div></div>必须在nav-link内部,且宽度用内联style或 CSS 变量动态控制 - 进度条高度别写死——用
h-1(4px)或h-2(8px),避免在小屏上过粗 - 需要堆叠多段进度?用 Bootstrap 原生的
progress-bar bg-success+bg-warning类组合,不用额外 JS - 进度值要可读?在
.progress-bar里加文本,但记得sr-only包裹,屏幕阅读器友好
响应式断点关键:重置 gap、padding 和 align-items
横向步骤条转竖排后,gap 会从水平间距变成垂直间距,若不重设,小屏上下步距离过大,视觉断裂。同时,align-items: center 在竖排时会让文字居中偏移,必须覆盖。
- 在
@media (max-width: 576px)里重写:.step-nav { gap: 1.5rem; }(别依赖gap-4,它在 flex column 下行为不稳定) -
.nav-link { padding: 0.75rem 1rem; align-items: flex-start; }—— 强制文字左对齐,不随内容高度浮动 - 箭头线(如用
border-left)需排除第一步:.nav-item:not(:first-child) .nav-link { border-left: 2px solid #e9ecef; } - 如果后端渲染,确保
aria-current="step"属性服务端输出准确;否则 React/Vue hydrate 后状态不同步
为什么别用 BootstrapBlazor 或第三方 Steps 组件?
像 BootstrapBlazor 的 Step IsVertical="true" 看似省事,但它依赖 Razor 渲染和客户端 JS 初始化,在 SSR/SEO 场景下易出问题;且它的 step-vertical 类是黑盒,无法微调竖线长度、进度条位置、键盘导航顺序等细节。
- 原生方案可控点更多:比如某步要禁用但保留焦点(用于键盘 tab 导航),只需
tabindex="-1"+aria-disabled="true",而组件往往只提供disabled开关 - 性能更轻:零 JS 依赖,首屏直出,无 hydration 水合延迟
- 兼容性更强:Bootstrap 5.3+ 的
flex-column和progress在所有现代浏览器中表现一致,不像某些组件在 Safari 上进度条动画卡顿 - 真正难的不是写代码,而是让每步的
aria-current、键盘焦点、屏幕阅读器播报、视觉状态四者严格同步——这只能靠手动控制 DOM 属性,不是靠组件自动推导


















