子列表必须作为li的直接子元素,否则结构断裂、编号重置、屏幕阅读器无法识别层级;ol嵌套编号不连续时需用CSS counter实现“1.1”格式,混用ul/ol须基于语义且不可依赖list-style-type控制编号。

ul 和 ol 本身不是“文本标签”,而是语义化列表容器;真正能嵌套的只有 li,且子列表(ul 或 ol)必须作为 li 的直接子元素,否则结构断裂、编号重置、屏幕阅读器无法识别层级。
为什么子列表写在 ul 里却没嵌套效果
浏览器会自动修正非法结构:把本该嵌在 li 里的 ul 或 ol 提到同级,变成两个独立列表。后果包括:
- DOM 中子列表不再是父
li的子节点,JS 查询li.querySelector('ul')返回null - 屏幕阅读器读作“列表,2 项”+“列表,3 项”,而非“列表,2 项,其中第 2 项包含子列表”
-
ol内层编号永远从 1 开始,不是 1.1、1.2 - CSS 选择器如
li > ul失效,样式无法精准命中
ol 嵌套时编号不连续(如要 1.1、1.2)怎么办
原生 ol 不支持跨层编号继承,type 和 start 都只作用于当前层。可靠方案是 CSS counter:
- 给外层
ol设counter-reset: section - 每层
li都要counter-increment: section - 用
li::before { content: counters(section, ".") ". "; }拼接层级 - 内层
ol必须也设counter-reset: section,否则计数器会继承上层值导致重复
示例片段:
<ol class="multi-level">
<li>第一项</li>
<li>第二项
<ol>
<li>子项一</li>
<li>子项二</li>
</ol>
</li>
</ol>
配合 CSS:
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
.multi-level { counter-reset: section; }
.multi-level > li { counter-increment: section; }
.multi-level > li::before { content: counters(section, ".") ". "; }
.multi-level ol { counter-reset: section; }
ul 和 ol 能不能混着嵌套
可以,但必须基于语义,不是为了换符号而硬套:
-
ol套ul:适合“有序步骤中某步含并列选项”,例如“3. 配置(数据库、缓存、日志)” -
ul套ol:适合“并列分类下有明确顺序的子流程”,例如“开发环境 → 1. 安装 Node.js → 2. 初始化项目” - 别用
ul套ol然后强行加list-style-type: decimal——它没有计数器语义,无法参与counter管理 - 混用时缩进控制要统一,推荐全部用
padding-left,禁用margin-left(各浏览器 UA 样式差异大)
超过三层嵌套还用 ul/ol 吗
技术上允许,但实际应避免:
- 第四层
ol type="i"在 Safari 可能 fallback 成数字,在 Chrome 渲染为 i., ii. —— 行为不可靠 - 屏幕阅读器播报“列表,2 项,子列表,3 项,子子列表,4 项”,用户极易迷失
- 键盘 Tab 导航深度增加,焦点管理变复杂
- 真需要四层以上结构(如法规条文),优先考虑
details+summary,它原生支持折叠、键盘操作和语义明确
最常被忽略的一点:嵌套是否必要,取决于内容逻辑,而不是视觉缩进需求。如果只是为了“看起来像树”,用 CSS padding + list-style 就够了;如果要传递“某一项的展开说明”这个语义,才必须用 li 包裹子列表。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










