必须用counter-reset和counter-increment禁用默认序号,再通过::after插入自定义后缀;需设list-style:none防重叠,content中空格须显式书写,动态切换推荐class控制而非JS直接操作DOM。

用 counter-increment + ::after 实现自定义后缀
原生 <ol> 只支持在项前显示序号,无法直接在每项末尾加文字(比如“——完成”)。必须借助 CSS 计数器和伪元素,绕过 HTML 结构限制。
核心思路:禁用默认序号,手动用 counter-increment 控制计数,再用 ::after 在每项末尾插入内容 + 自定义文本。
- 必须给
<ol>设置counter-reset(如counter-reset: item) -
<li>需设counter-increment: item,否则计数不递增 -
<li>::after里用content: counter(item) " ——已完成",注意引号内空格要显式写入 - 别忘了加
list-style: none关掉浏览器默认序号,否则新旧序号会叠在一起
ol {
counter-reset: item;
list-style: none;
}
ol li {
counter-increment: item;
}
ol li::after {
content: " ——已完成";
}
如果想保留原有序号并追加文字
不能直接用 list-style-type,因为它的位置固定在项前。得把原有序号“抢”出来:用 counter(item) 替代默认序号,再拼接后缀。
- 去掉
list-style,改用::before插入序号 + 点号 + 空格 -
::after单独负责追加文字,和::before互不干扰 - 例如:
content: counter(item) ". "(::before),content: "✅"(::after) - 注意
::before和::after默认是 inline 级,若需对齐可加display: inline-block或调整margin
JavaScript 动态追加时的坑
如果用 JS 往 <li> 里 appendChild 或修改 textContent,容易覆盖原有内容或破坏结构。更稳妥的是只操作伪元素可控的部分。
立即学习“前端免费学习笔记(深入)”;
- 避免直接改
li.innerHTML,否则可能把::after触发逻辑搞乱(虽然伪元素不进 DOM 树,但样式依赖结构) - 需要动态切换后缀时,推荐用 class 控制:
li.classList.add("done"),再写.done::after { content: " ——已归档" } - 若必须 JS 注入真实文本节点,建议插在
li内部末尾:li.append(document.createTextNode(" ——临时备注")),但这样无法用 CSS 控制样式或条件显示
IE 兼容性与 fallback 方案
::after 和 counter() 在 IE8+ 基本可用,但 IE8 不支持 content 里的 counter() 函数——它只认固定字符串。所以真要兼容老版本,得换思路。
- IE8 及以下:放弃 CSS 计数器,改用 JS 遍历
ol li,手动设置data-index,再用 JS 拼后缀插入到每个li末尾 - 现代项目中,只要不需支持 IE,CSS 方案足够简洁稳定;但要注意
counter()不支持小数、字母序号等复杂类型(如 a, b, c),此时得用list-style-type: lower-alpha+ JS 补位 - 移动端 Safari 对
counter()渲染偶有延迟,若发现首次加载没显示后缀,加个transform: translateZ(0)强制硬件加速可缓解
li 的 display 类型(比如改成 flex),::after 的定位就可能偏移——这时候得回头检查 content 是否被继承、white-space 是否截断、父级是否设置了 overflow: hidden。



















