法律条款必须用确保语义正确和可访问性,所有条款须包裹在同一内,每条为,子款嵌套在父内;编号用css计数器实现“第x条”,禁用type属性硬编码。

法律条款必须用 <ol></ol>,不是为了编号而是语义正确
法律条文天然具有顺序依赖和引用需求,“第3条”“参见第7款”这类表述意味着编号不可跳过、不可乱序、不可语义模糊。用 <ul></ul> 或纯 <p></p> 拼编号,屏幕阅读器会读成“列表第1项”“列表第2项”,但用户无法判断这是“第1条”还是“第1点注意事项”。只有 <ol></ol> 能向辅助技术传达“这是有法定顺序的条款序列”。
常见错误现象:<ol type="1"></ol> 里混写 <div> 或直接放文本;或把多个 <code><ol></ol> 并列写(如每条单独一个 <ol></ol>),导致每条都从“1.”开始,且 DOM 中失去整体条款容器。
- 所有条款必须包裹在同一个
<ol></ol>内,每条为一个<li> - 禁止在
<ol></ol>内直接写文字,必须用<li>包裹全部内容 - 若条款含子款(如“第5条第2款”),子款必须是上一级
<li>的**直接子元素**,即<li><ol><li>…</li></ol></li>,不能脱离父<li>
start 属性只改显示数字,不跳过实际条款
想让文档从“第4条”开始?写 <ol start="4"></ol> 即可。但它不会隐藏前3条——它只是让第一条 <li> 显示为 “4.”,后续自动为 “5.”、“6.”。这适合续订法规、修订版等场景。
真正需要“跳过已废止条款”时,start 无效:屏幕阅读器仍按 DOM 位置读“第1项”,而非“第4项”。此时必须配合 ARIA:
- 给整个
<ol></ol>加aria-setsize="10"(假设共10条) - 给首条有效条款的
<li>加aria-posinset="4" - IE 不支持
start,旧环境需服务端预渲染或 JS 补位
“第X条”这种中文前缀,别碰 type 属性
type="1" / type="A" 只能输出阿拉伯数字或字母,无法生成“第1条”“第2条”。硬编码文字(如 <li>第1条 内容</li>)会破坏语义、无法批量样式控制、增删条款时极易出错。
正确做法是用 CSS 计数器:
ol {
counter-reset: article;
}
ol li {
counter-increment: article;
}
ol li::before {
content: "第" counter(article) "条 ";
font-weight: bold;
}
注意:counter-reset: article 必须写在 <ol></ol> 上;counter-increment 必须写在 <li> 上;漏掉任一环节,::before 里只会显示 “第0条”。若要从第5条开始,写 counter-reset: article 4(值是起始编号减1)。
嵌套子款编号容易断层,关键看 DOM 是否闭合
法律中常见“第8条第1款”“第8条第2款”,很多人写成两个并列 <ol></ol>,结果子款全变成“1.”。正确结构是子 <ol></ol> 必须作为父 <li> 的**唯一直接子块级元素**:
<ol>
<li>第8条内容
<ol>
<li>第1款内容</li>
<li>第2款内容</li>
</ol>
</li>
</ol>
常见坑:<li> 里先写文字再写 <ol></ol>,但没用 <p></p> 或 <span></span> 包裹文字,导致浏览器把文字当 <li> 的文本节点,而 <ol></ol> 成为孤立标签——此时子款编号重置为 “1.”,且可访问性树断裂。
复杂条款(如带附录、跨章引用)建议放弃纯 CSS 计数器,改用 data-article="8" + JS 初始化,确保编号与后端数据一致,避免 DOM 和业务逻辑脱节。











