HTML的<ol>嵌套时默认重置编号,子列表从1开始而非继承父级序号;需用CSS counter-reset与counter-increment配合::before实现视觉连续编号(如1.1),但语义上仍为独立列表。

有序列表默认就是连续编号,但嵌套时会重置
HTML 的 <ol> 元素天然按顺序编号,只要不中断(比如没关闭标签、没意外插入其他块级元素),编号就会自然延续。真正出问题的场景是嵌套使用——比如在某个 <li> 里又写了一个 <ol>,这时子列表会从 1 开始,而不是继承父级当前序号。
常见错误现象:
父列表第 3 项里嵌了子列表,结果子列表显示 “1. …”,而不是 “3.1. …” 或延续为 “4. …”。这不是 bug,是规范行为。
- 子
<ol>默认独立计数,和父级无关 - 浏览器不会自动做“多级编号拼接”(如 2.1、2.2)
- 若想视觉上延续,需用 CSS
counter-reset+counter-increment手动控制
用 CSS counter 实现跨层级连续编号
当需要让嵌套的 <ol> 接着上一级编号继续(比如父级到 5,子列表从 6 开始),就得绕过默认行为,用 CSS 计数器接管。
关键点在于:不在子 <ol> 上调用 counter-reset,并确保它的 counter-increment 延续父级计数器。
立即学习“前端免费学习笔记(深入)”;
- 给最外层
<ol>设置counter-reset: item - 每个
<li>用counter-increment: item - 子
<ol>不设counter-reset,让它复用同一计数器 - 用
::before { content: counters(item, ".") ". " }可实现多级点分格式(如 1.1、1.2),但注意这仍是视觉拼接,不是语义连续
ol { counter-reset: item; }
li { counter-increment: item; }
li::before { content: counters(item, ".") ". "; }
ol ol { /* 不 reset,直接继承 */ }
start 属性只适用于单层手动起始,不能自动衔接
start 是 <ol> 的原生属性,比如 <ol start="5"> 会让第一个 <li> 显示为 “5.”。但它只是硬编码起点,无法读取前一个列表的末尾值。
- 适合静态已知起始位置的场景(如分页后接续)
- 如果前一个列表动态生成、项数不确定,
start就没法自动对齐 - 它对嵌套子列表无效——子
<ol>加start也只是覆盖自己的初始值,不影响父级逻辑 - 和 CSS counter 机制互不干扰,但混用容易混乱,建议二选一
语义与可访问性:连续编号 ≠ 连续 <li> 结构
屏幕阅读器依赖 HTML 结构判断列表关系,不是靠 CSS 视觉编号。强行用 CSS 把两个分离的 <ol> 看起来连续,但语义上仍是两个独立列表,可能被读作“列表 1,共 3 项;列表 2,共 4 项”,而非“一个列表共 7 项”。
- 如果逻辑上本就是一个列表,就别拆成多个
<ol>,用<li>嵌套即可(<li><ol>...</ol></li>) - 如果必须物理拆分(如 CMS 分段渲染),CSS counter 是唯一可行方案,但得接受语义断层
- 避免用
list-style-type: none+ 伪元素模拟编号来替代真实<ol>,这会让无障碍支持彻底失效
真正难的不是让数字看起来连续,而是让结构、样式、语义三者不打架。多数时候,先想清楚“为什么需要跨容器连续”,比急着写 CSS counter 更重要。



















