必须用<ol>而非<ul>或<div>,因其天然支持序号语义、无障碍访问(屏幕阅读器自动读“第1项”)及CSS计数器自动编号;<ul>丢失顺序语义,<div>完全无结构,损害SEO与辅助技术识别。

<ol> 是唯一合理的选择,用 <div> 或 <ul> 做水平步骤条,等于主动放弃语义、可访问性和响应式稳定性。
为什么必须用 <ol> 而不是 <ul> 或 <div>
步骤有天然顺序,“第1步→第2步→第3步”不是并列关系,<ul> 会丢失这个语义,屏幕阅读器读出来就是“列表,3项”,不带序号也不带先后;<div> 更糟,完全无结构,SEO 和辅助技术都当它不存在。而 <ol> 浏览器默认渲染数字,且支持 counter-reset 和 ::before 自定义序号,无需 JS 插入、不卡首屏。
- 别给
<ol>设list-style: none后再用伪元素重画数字——这是多此一举,反而可能破坏高对比度模式下的可读性 - 如果项目要求从 0 开始或跳号(如“Step A / Step B”),用
start属性或 CSScounter-set控制,不要删原生序号 - 嵌套在
<nav>里加aria-label="步骤导航",比单独加role="navigation"更准确
display: flex 布局时连接线怎么画才不翻车
连接线本质是前 n−1 个步骤的右侧延伸,不是每个步骤都该有线。用 ::after 加在 li:not(:last-child) 上最稳,宽度设为 calc(100% - 40px)(预留左右圆点空间),再用 transform: translateY(-50%) 垂直居中。
- 别用
border-right——缩放后虚线错位、高对比度下消失 - 别给最后一个
li写::after { display: none },直接用:not(:last-child)选择器更干净 - 移动端切
flex-direction: column时,记得同时display: none所有连接线,否则竖排还挂着横线
状态切换只改一个 class,但 aria 属性必须同步更新
JS 切换步骤时,光加 is-active 不够。屏幕阅读器只认 aria-current="step",且必须配 tabindex="0" 才能被键盘聚焦。漏掉任意一项,无障碍测试就挂。
立即学习“前端免费学习笔记(深入)”;
- 当前步:加
aria-current="step"+tabindex="0" - 已完成步:加
aria-label="已完成:填写信息",不能只写✓ - 未开始步:加
aria-disabled="true"+tabindex="-1",禁用键盘进入 - 每次切换前,先用
querySelectorAll('[aria-current]')清掉旧的aria-current,再设新的——避免残留
真正难的不是让线连起来,而是让每一步的状态在 DOM、CSS、ARIA、键盘焦点四个层面始终一致。少同步一环,用户就可能卡在“看不见、点不到、读不出”的死循环里。


















