counter-reset 不响应媒体查询切换,只在渲染时初始化一次;需在每个断点内对实际渲染的父容器重置计数器,并确保作用域与DOM结构严格匹配。

counter-reset 本身不响应媒体查询切换——它只在元素渲染时初始化一次,所以直接套用在根容器上,移动端展开/折叠后编号必然错乱。
为什么@media里改display或visibility后编号不变?
常见错误是给 .toc 设 counter-reset: section subsection;,再靠 @media 控制子项显隐。但问题在于:counter-increment 按 DOM 顺序执行,不受 display: none 或 visibility: hidden 影响;counter-reset 也只触发一次,不会因媒体查询生效而重置。
- 桌面端有 8 个
li,编号为 1–8;切到移动端后仅显示前 3 个(其余display: none),编号仍是 1–3,而非重新从 1 开始 -
visibility: hidden的项仍参与计数;display: none的项则被跳过(这是预期行为,但常被误读为 bug) - 伪元素
::before的content只读取当前计数器值,不感知“当前可见项有多少”
必须在每个断点内对实际渲染的父容器重置计数器
不是“写一遍就行”,而是确保每次布局变更后,counter-reset 作用域与当前 DOM 渲染结构严格匹配。关键看谁是当前层级的逻辑父容器。
- 桌面端用
grid布局:在.toc上设counter-reset: section subsection;,并在.toc > li和.toc ul li分别counter-increment - 移动端用垂直流式:同样要在
.toc上重置(不能省略!),否则继承桌面残留状态,二级编号可能全为 0 或跳成负数 - 注意选择器精度:
.toc ul和.toc > ul触发时机不同,需按真实 HTML 结构调整,比如嵌套ul在li内,就得用.toc li ul
多级编号必须分层定义独立计数器名
别用同一个名字嵌套重置——counter-reset: item 在子 ol 里会清零父级计数器,导致二级永远从 1 开始。要实现 “1.1、1.2、2.1”,得靠命名隔离。
- 一级用
counter-reset: level1;,二级用counter-reset: level2;,互不干扰 - 二级
li必须同时counter-increment: level1 level2;,否则level1不随嵌套推进 - 输出用
counters(level1, "."),而不是拼接counter(level1)+ "." +counter(level2)—— 后者在折叠/展开时易断层 - 三级及以上每层新增一个计数器名,如
level3,并同步加counter-reset和counter-increment规则
伪元素 display 和对齐容易被忽略
序号是 ::before 生成的文本,在 flex 或 grid 容器中默认 display: inline,极易换行、错位或被截断,看起来像“编号消失”。
立即学习“前端免费学习笔记(深入)”;
- 必须显式设
display: inline-block或display: flex,避免换行 - 用
min-width: 2em+text-align: right对齐数字,防止 “10.” 挤压内容 - 若父容器是
grid,建议用grid-column: 1锁定序号列,内容从第 2 列开始 -
white-space: nowrap防止编号中间的点号被折行


















