HTML 中 ol 嵌套必须严格在 li 内部,否则编号重置;type 属性仅控制单层样式,跨层级连续性依赖合法嵌套结构;实现 1.1 类编号须用 CSS counters() 而非 start 属性。

ol 嵌套必须严格在 li 内部,否则编号重置
浏览器对 <ol> 的层级计数依赖 DOM 结构合法性。如果你把子 <ol> 放在父 <ol> 外面(比如紧接在 </ol> 后),哪怕只隔一个空格或换行,它都会被当成全新列表——第二级永远从 A 或 1 开始,而不是延续前序。
常见错误现象:<ol type="A"><li>A. First</li></ol><ol type="1"><li>1. Sub</li></ol>,结果是 A. → 1.,而非 A.1.;<ol type="1"><li>1. Main</li></ol><ol type="a"><li>a. Sub</li></ol> 同样会断层。
- ✅ 正确写法:子
<ol>必须作为某个<li>的直接子内容,不能脱离 - ✅ 示例结构:
<ol type="A"><li>A. Title<ol type="1"><li>1. Sub</li></ol></li></ol> - ⚠️ 注意:
<p>、<div>等非<li>容器内嵌<ol>,会导致语义断裂和编号错乱
用 start 属性控制外层起始编号,但别指望它影响子层前缀
start 只作用于当前 <ol> 的第一项数值(如 start="34" 让首项显示为 “34.”),但它不会自动变成子层编号的前缀(比如不会让子项变成 “34.1”)。想实现这种效果,必须靠 CSS counters(),不是靠 HTML 属性。
使用场景:法律条文、比赛规则等需要章节号继承的场合(如第 34 条下的 34.1、34.2)。
立即学习“前端免费学习笔记(深入)”;
- ✅ 若只需简单起始值:直接用
<ol start="34">,子层用<ol type="a">即可 - ✅ 若需拼接前缀(如 34.1):必须配合 CSS:
ol ol li::before { content: counters(list-item, ".") " "; } - ⚠️ 切记:
counters(list-item, ".")依赖浏览器内置的list-item计数器,不要手动counter-reset,否则会破坏继承逻辑
type 属性决定编号样式,但跨层级连续性由嵌套结构保障
type 控制单层编号类型("1"、"a"、"A"、"i"、"I"),但它本身不保证跨层级连续。B. 出现在 A. 之后,不是因为 type="A" 有“记忆”,而是因为第二个 <li> 在同一个父 <ol> 下。
性能与兼容性影响:所有现代浏览器都支持 type,但 IE8 及更早版本对 type="i" / type="I" 支持不稳定,生产环境建议降级为 type="1" + CSS 伪元素模拟。
- ✅ 推荐组合:
<ol type="A">→<ol type="1">→<ol type="a">→<ol type="i"> - ✅ 深层嵌套时,避免超过 4 层,否则可访问性(屏幕阅读器)和打印样式易出问题
- ⚠️
type="1"是默认值,可省略;但显式写出更利于团队协作和代码自解释
用 counters() 实现 1.1、2.3.2 这类带点分隔的多级编号
这是唯一能可靠生成形如 “2.3.2” 编号的方式,且无需 JavaScript。核心是复用浏览器内置的 list-item 计数器,用 counters() 函数递归拼接。
容易踩的坑:给 ol 加了 list-style-type: none 却忘了在 ::before 里补上 content,结果编号全消失;或者误用 counter()(单层)代替 counters()(多层)。
- ✅ 必须移除默认样式:
ol { list-style-type: none; } - ✅ 关键 CSS:
ol ol li::before { content: counters(list-item, ".") " "; } - ✅ 若只想从第二层开始编号(跳过第一层数字),加
ol > li::before { content: none; } - ⚠️
counters()第二个参数是字符串分隔符,必须用英文引号包裹,如"."或"–",不能写成.
start 和 type 更脆弱,也更容易被忽略。



















