HTML规范规定ol的start属性必须为正整数,0会被重置为1;推荐用CSS counter-reset: item -1配合::before生成“0, 1, 2…”序号,兼顾语义、兼容性与可访问性。

ol 的 start 属性不支持 0 开头
直接写 <ol start="0"></ol> 在大多数浏览器里会自动 fallback 到 1,不是 bug,是 HTML 规范明确规定的:start 属性值必须是正整数(1 或更大),0 和负数会被忽略或重置为 1。所以指望原生 ol 配合 start 实现 “0, 1, 2…” 序号,行不通。
CSS counter-reset 强制从 0 开始计数
这是目前最干净、语义正确且兼容性良好的方案:用 CSS 重置计数器起始值,再覆盖默认序号显示。关键点在于避开 start 的限制,改用 CSS 控制。
实操建议:
- 给
ol设置counter-reset: item -1(注意是-1,因为::marker渲染前会先 increment) - 用
ol li::marker或ol li:before显式生成序号,配合counter-increment - 必须取消默认序号,否则会叠加显示:加
list-style: none到ol或li
最小可用示例:
<ol class="zero-start">
<li>第一项</li>
<li>第二项</li>
</ol><style>
.zero-start {
list-style: none;
counter-reset: item -1;
}
.zero-start li::before {
content: counter(item) ". ";
counter-increment: item;
}
</style>
JavaScript 动态补零需谨慎
如果列表内容动态生成、或需兼容极老浏览器(如 IE11 及更早),可能考虑 JS 注入序号。但要注意副作用:
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 破坏可访问性:屏幕阅读器可能读不到手动插入的文本序号
- 影响打印样式:
::before通常能打印,而 JS 插入的textContent可能被忽略 - 序号与 DOM 脱节:后续 JS 操作
li时,容易误判索引(比如li[0]对应的是 “0.”,但逻辑上常期望它是第一个有效项)
若仍需 JS 方案,推荐只操作 li 的 value 属性(仅对 ol 有效),但注意:该属性仅影响当前 li 及之后的序号,无法真正“全局归零”。例如:
<ol> <li value="0">这会显示 0</li> <li>这会显示 1</li> <li>这会显示 2</li> </ol>
但这个 value="0" 是非法 HTML(验证器报错),且部分浏览器(如 Safari)会无视它。
服务端/模板层预处理更可控
如果你用的是 React/Vue/SSR 或静态站点生成器(如 Hugo、Jekyll),在渲染阶段就生成带零序号的结构,是最稳妥的:
- 避免 CSS 兼容性博弈(比如某些旧版 Android WebView 对
::marker支持弱) - 序号成为真实 DOM 文本,无障碍和 SEO 更友好
- 可自由控制格式,比如 “00”, “0.1”, “item-0” 等非数字前缀场景
例如 Vue 模板中:
<ol>
<li v-for="(item, index) in list" :key="index">
<span class="prefix">{{ index }}.</span>
{{ item.text }}
</li>
</ol>
CSS 方案看似简单,但 counter-reset: item -1 这个初始值容易记错成 0;JS 的 value 属性看似直观,实则游走在规范边缘;真正稳定的做法,往往发生在 HTML 渲染之前。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










