空li元素会导致编号错乱:Chrome/Safari跳过空li不计数,Firefox计入序号,造成视觉编号与DOM顺序脱节;规范未明确定义空项是否参与计数,故非bug。

空 li 元素会导致编号错乱
浏览器对 ol 中空 li 的处理不一致:Chrome 和 Safari 会跳过空 li 不计数,Firefox 则仍计入序号,导致视觉编号(1,2,4)和 DOM 顺序(1,2,3,4)脱节。这不是 bug,而是规范未明确定义空项是否参与计数的结果。
实操建议:
- 永远避免写
<li></li>或仅含空白字符的li;用开发者工具检查元素是否真的为空(含空格、换行也算“非空”,但可能渲染为不可见) - 若需占位但不显示内容,改用
li内嵌<span style="visibility: hidden"></span>或<span aria-hidden="true"></span>,保持计数连续 - 服务端或模板引擎生成列表时,过滤掉空值再输出
li,比前端补救更可靠
start 属性无法修复已存在的空项
start 只影响第一个 li 的起始数字,它不会重排后续项。例如 <ol start="3"><li>A</li><li></li><li>B</li></ol> 在 Firefox 中显示为 “3. A” → “4.” → “5. B”,空项仍占位。
关键区别:
立即学习“前端免费学习笔记(深入)”;
-
start是 HTML 属性,作用于整个ol,只设开头 -
value是li的属性,可强制单个项编号(如<li value="7">第七步</li>),但会破坏自动续编逻辑 - 混用
start和value容易引发编号跳跃,调试困难
CSS :nth-of-type() 不能跳过空 li
想用 li:nth-of-type(n + 3) 隐藏第 3 项之后的编号?没用——伪类选择器按 DOM 位置匹配,空 li 仍是 li 元素,照样被选中。隐藏它只会让内容消失,编号逻辑照旧错乱。
真正有效的做法:
- 用 JavaScript 遍历
ol li,el.textContent.trim() === ""时调用el.remove()(注意:移除后ol的reversed或type行为不变) - 若必须保留 DOM 结构(如 SSR 渲染),加 class 如
li.empty,再配 CSS:li.empty { list-style-type: none; padding-left: 0; },并确保其无内容高度不塌陷 - 辅助技术友好性:空
li仍可能被读屏软件播报为“列表项”,应设aria-hidden="true"
嵌套有序列表里空 li 更危险
在 ol > li > ol 这类结构中,父级 li 为空,会导致子 ol 的 start 计算异常,尤其当子 ol 依赖父项编号推导起始值时(比如步骤 2.1、2.2)。此时空项不仅影响当前层级,还会污染下层编号上下文。
预防措施:
- 禁止在嵌套场景中使用空
li,宁可用注释<!-- placeholder for step 3 -->占位 - 如果内容动态加载,等数据到达后再插入完整
li,而非预先塞空壳 - 测试时用屏幕阅读器验证:空
li是否被误读为“空白列表项”,这比视觉错位更损害可访问性
空 li 看似微小,但它同时扰动编号逻辑、CSS 选择器行为和辅助技术解析——三者叠加后,问题往往在上线后才暴露,且难以复现。最稳妥的方式,是从模板层就拒绝空值进入 li。



















