子列表必须完整嵌套在标签内,否则浏览器会自动修复结构导致嵌套失效;用于有序流程,用于无序并列;多层嵌套需控制在三层内并用CSS counter实现编号。

子列表必须完整写在 <li> 标签内部
浏览器解析时,只要 <ul></ul> 或 <ol></ol> 的直接子元素不是 <li>,就会自动“修复”结构——把非法内容拆成独立块,导致嵌套失效。比如写成:<ol><li>第一步</li></ol>
<ul><li>子项</li></ul>,实际渲染为两个并列列表。
正确写法只有一条:子列表(无论 <ul></ul>、<ol></ol> 还是 <dl></dl>)必须从 <li> 开始标签之后、结束标签之前完整存在。用开发者工具检查 DOM,确认子列表节点确实在父 <li> 下,而不是同级节点。
- 错误示例:
<ul>水果<ul><li>苹果</li></ul> </ul>→ “水果”变成文本节点,子<ul></ul>被移出 - 正确示例:
<ul><li>水果<ul><li>苹果</li></ul> </li></ul> -
<li>内可嵌套任意合法内容:<p></p>、<div>、<code><ul></ul>、<ol></ol>,甚至多层嵌套<ol></ol>和<ul></ul>的语义选择不能混用目录、步骤流程这类天然有序的结构,必须用
<ol></ol>;并列分类、标签云、导航菜单等无顺序依赖的,才用<ul></ul>。用<ul></ul>套编号样式只是视觉模拟,丢失了语义、屏幕阅读器播报和 SEO 结构化数据支持。-
<ol type="A"></ol>适合附录节(A.1、A.2),start="3"可跳过前序编号 - 混合嵌套常见且合理:
<ol></ol>描述步骤,其中某步内用<ul></ul>列出并列选项(如“配置项:数据库、缓存、日志”) - 避免用
list-style-type: decimal;强行给<ul></ul>加数字——它不提供计数器语义,无法配合counter-reset实现“2.1”式编号
缩进与编号样式异常的根源和修复方式
默认缩进来自浏览器对每层
<ul></ul>/<ol></ol>的padding-left累加,不是 bug,但多层后容易错位。别用text-indent修——它只影响第一行,对换行<li>无效。- 统一重置基础缩进:
ul, ol { padding-left: 2rem; } - 逐层微调:
ul ul, ol ul, ul ol { padding-left: 1.5rem; } - 要实现“1.1”“1.1.1”编号,必须用 CSS
counter-reset+::before,例如:ol { counter-reset: item; } li { counter-increment: item; } li::before { content: counters(item, ".") ". "; } - 旧版 IE 不支持
counters(),需降级为固定符号或 JS 补充生成
嵌套层级超过 3 层时的实际风险
技术上允许无限嵌套,但超过三层会显著增加维护成本和无障碍负担。屏幕阅读器会播报“列表,2 项,子列表,3 项,子子列表,4 项”,用户极易迷失;CSS 缩进叠加也更难控制。
- 三级以内(如章→节→小节)是安全边界;四级如“2.1.1.1”建议重构:拆分文档、用
<details></details>+<summary></summary>折叠,或引入 JS 控制展开逻辑 - 每层
<li>必须含非空文本内容,否则会被屏幕阅读器跳过,导致嵌套结构“不可见” - 最常被忽略的是驱动嵌套的动因——是内容逻辑真需要展开,还是仅仅为了视觉缩进?HTML 结构一旦写错,CSS 很难挽救语义缺陷
-











