display: flex + data-status 是最稳的起点,纯 CSS 实现语义、状态、响应式;用 <ol> + counter 自动编号;连线仅作用于非首项;伪元素绝对定位居中;flex: 1 + min-width: 0 等分;横排::before、竖排::after画线;状态变更需JS与CSS严格对齐。

display: flex + data-status 是最稳的起点,纯 CSS 就能跑通语义、状态、响应式三关,不需要 JS 渲染结构。
用 <ol> + counter 实现自动编号和语义化
别用一堆 <div> 手写 1/2/3,既难维护又破坏可访问性。有序列表 <ol> 天然表达步骤顺序,配合 CSS 计数器自动生成序号:
<ol class="steps"><li data-status="done">登录</li><li data-status="active">填写信息</li></ol>- CSS 中写
.steps { counter-reset: step; },再用li::before { content: counter(step); counter-increment: step; } - 序号样式(颜色、边框、圆点)全由
data-status控制,比如li[data-status="done"]::before { color: #198754; }
.steps li:not(:first-child)::before 画连接线才不会多出一根
所有 li::before 都加线,第一个节点左边就会多一条虚线,而且绝对定位容易塌陷。正确做法是只作用于非首项:
-
.steps li:not(:first-child)::before精准限定范围 - 用
position: absolute; top: 50%; left: -50%; transform: translateY(-50%)把伪元素中心对齐当前节点左边缘 -
width: 100%才能刚好连到上一节点中心;用background-color比border更可控,不干扰盒模型 - 连线颜色靠兄弟选择器驱动:
li[data-status="done"] + li::before { background: #198754; }
Flex 等分节点必须配 min-width: 0 和 flex: 1
写死 width: 25% 在 3 步/5 步/文字变长时必然错位。Flex 天然适合等分,但有两个硬约束:
- 父容器设
display: flex; justify-content: space-between;,子项不设 width,只写flex: 1; - 必须加
min-width: 0,否则长文本(如“确认支付信息”)会撑开节点,flex: 1失效 - 文字换行后高度不一致?统一用
align-items: center+line-height垂直居中,别依赖padding
移动端竖排连线要用 ::after 而不是复用 ::before
横排用 ::before 画水平线没问题,但小屏切竖排时,同一伪元素很难兼顾方向和定位。更可靠的做法是:
立即学习“前端免费学习笔记(深入)”;
- 横排保持
li:not(:first-child)::before画线 - 竖排媒体查询里改用
li:not(:last-child)::after画border-bottom或height连线 - 避免用
transform: rotate()或linear-gradient斜向模拟——折行后极易偏移,尤其在 iOS Safari 上
data-status 时,必须同步校验有效性,否则第 2 步标成 done,但第 3 步的连线颜色没跟着变,用户一眼就看出逻辑脱节。


















