ol 本身不支持折叠,强行用 display: none 隐藏子 ol 会破坏语义、编号和可访问性;正确方案是用 details + ol 组合实现语义化折叠,既保留编号逻辑又获得原生折叠能力。

ol 本身不支持折叠,强行用 display: none 隐藏子 ol 会破坏语义、编号和可访问性——这不是样式问题,是结构误用。
为什么不能直接对嵌套 ol 做折叠
浏览器强制要求子 ol 必须完整嵌套在父 li 内部,否则编号重置、DOM 层级断裂、屏幕阅读器无法识别层级关系。哪怕 CSS 看起来缩进正确,只要子 ol 不在 li 标签内,语义就已失效。
- 常见错误:
—— 第二个- 一级项
- 二级项
ol已脱离上下文,永远从 1 开始编号 -
type属性不继承,ol[type="A"] > li > ol不会自动变成数字编号,必须显式写type="1" - 用
visibility: hidden或height: 0控制显隐,仍占用布局空间,且无法触发键盘焦点或屏幕阅读器播报
替代方案:用 details + ol 组合实现语义化折叠
把每层 ol 的父级 li 替换为 details,让 summary 承担标题,内部再放 ol。这样既保留编号逻辑,又获得原生折叠能力。
示例结构:
<ol>
<li>
<details><summary>第一章:入门</summary><ol>
<li>安装环境</li>
<li>Hello World</li>
</ol></details>
</li>
<li>
<details><summary>第二章:进阶</summary><ol>
<li>异步编程</li>
<li>错误处理</li>
</ol></details>
</li>
</ol>
-
summary必须是details的第一个子元素,否则点击无效 - 编号由外层
ol和内层ol各自独立控制,互不影响 - 无需 JS 即可键盘操作(空格/回车),屏幕阅读器能准确播报“已展开”“已折叠”
- Safari 对
summary::marker支持弱,建议用summary::before+transform: rotate()控制箭头方向
如果必须用纯 ol 结构,折叠只能靠 JS 模拟,但代价很高
你得放弃原生编号,改用 CSS counters() 生成带前缀的序号(如 1.1、2.1),再手动绑定点击事件控制 nextElementSibling 的显隐状态。
- 子
ol必须紧跟在li内部闭合标签后,否则nextElementSibling找不到目标 - 不能依赖
display: none初始隐藏——动态插入新项时易错乱,推荐初始全显,JS 控制类名切换 - 四级以上嵌套时,
counters()兼容性差(IE10– 不支持),且缩进累加易导致视觉偏移 - 每次展开/收起都要重新计算所有后代
li的counter-increment,性能敏感场景慎用
真正需要折叠的层级内容,details 是唯一兼顾语义、可访问性与开发效率的选择;硬套 ol 折叠,等于在语义断层上贴 CSS 胶布——短期能用,长期维护成本高,而且无障碍测试必然失败。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











