css grid 实现响应式步骤指示器最轻量可控,通过 grid-template-columns 动态分配连接线宽度、伪元素绘线、minmax 布局适配屏幕,并配合 word-break、状态数组驱动、usesteps hook 管理异步校验与无障碍焦点。

用 CSS Grid 实现响应式步骤指示器
纯 CSS 实现最轻量、最可控,不需要任何 JS 就能表达步骤状态和顺序。关键在于用 grid-template-columns 动态分配连接线宽度,再用伪元素画线。
常见错误是硬写固定像素的线长,导致小屏下溢出或断开;或者用绝对定位强行对齐,结果步骤文字换行后箭头错位。
- 每个步骤项用
<li>包裹,父容器设为display: grid,列模板设为repeat(auto-fit, minmax(120px, 1fr)))),保证小屏自动收缩 - 连接线用
::after在非末尾项上绘制,width: calc(100% + 24px)覆盖到下一个步骤中心(24px 是图标/数字宽度的一半) - 禁用
white-space: nowrap,否则中文长文本会撑破容器;改用word-break: break-word配合min-width: 0
用 Tailwind 实现带状态切换的步骤条
Tailwind 适合快速搭出可交互原型,但要注意状态类不能只靠 text-green-600 这类静态样式——实际业务中“已完成”“当前”“未开始”往往需要 JS 控制 class 切换。
容易踩的坑是把所有状态逻辑塞进 HTML 模板里,导致后续加个“跳回上一步”功能就得重写整个渲染逻辑。
- 步骤数据建议用数组驱动:
steps = [{ id: 1, label: '填写信息', status: 'done' }, ...],用map()渲染,避免手写多个<div class="..."> <li>连接线推荐用 <code><div class="absolute top-1/2 left-full w-8 h-0.5 bg-gray-300">,而不是 <code>border-r,后者在 flex 布局中易被截断 - 移动端点击区域要够大:给每个步骤项加
min-height: 48px和flex items-center,防止 iOS 上点击失灵 - Hook 返回值至少包含:
currentStep、goTo(step)、next()、prev()、isStepValid(step)、setStepError(step, msg) - 内部用
useReducer处理状态流转,比如{ type: 'SUBMIT_START', step: 2 }触发 loading 状态,避免多个useState同步问题 - 连接线是否显示,应由
isStepValid(i) && i 决定,而不是简单用 <code>i ,否则用户跳过未填步骤时线会连错 - 每个步骤项加
role="tab"、tabIndex="0"、aria-selected="true/false"、aria-disabled="true(对未激活步骤) - 监听
keydown事件,对Enter和Space都触发跳转,且跳转前调用e.preventDefault() - 跳转后必须手动
element.focus()到目标步骤项,否则焦点留在原地,键盘用户会迷失
React 中用 useSteps 管理步骤状态
自定义 Hook 是解耦的关键。不要在组件内直接用 useState(1) 管理当前 step,否则无法复用、无法透传错误状态、无法支持异步校验阻断。
典型问题是“下一步”按钮点了没反应——其实是校验失败但没反馈,或者异步请求还没返回就跳转了。
无障碍与焦点管理必须显式处理
默认的步骤指示器对键盘用户几乎不可用:Tab 键无法聚焦步骤项、屏幕朗读器读不出“第 2 步,已完成”,按空格/回车也无法触发跳转。
这不是“加上 role="tablist" 就完事”的事——真实场景中,用户可能用键盘跳到第 3 步再按回车,期望直接激活,而不是先聚焦再按一次按钮。
setStepError(2, '邮箱格式错误'),而不是等点击“下一步”才校验。











