页码必须用 CSS @page 规则配合 counter(page) 实现,Puppeteer 需启用 displayHeaderFooter: true,且 @page 必须位于顶层 CSS;分节页码需结合 counter-reset 与 counter-increment 控制。

HTML 转 PDF 时页码只能靠 CSS `@page` 实现
原生 HTML 不支持 `第1页` 这类写法在 PDF 中自动更新页码——浏览器打印或工具(如 wkhtmltopdf、WeasyPrint、Puppeteer)生成 PDF 时,页码必须由 CSS 的 @page 规则控制,且仅对块级内容生效。JavaScript 动态插入的页码文本在 PDF 渲染阶段早已失效。
用 @page + counter(page) 插入基础页码
这是最通用、兼容性最好的方式,适用于 Puppeteer、wkhtmltopdf、WeasyPrint 等主流工具(注意:部分旧版 wkhtmltopdf 对 counter() 支持不完整,建议用 0.12.6+)。
@page {
@bottom-center {
content: "第 " counter(page) " 页";
}
}
-
counter(page)是唯一被广泛支持的页码变量,不能写成page或pages -
@bottom-center可替换为@top-right、@bottom-left等,但位置关键词必须严格匹配(大小写敏感) - 不能在
@page内使用 class、id 或 JS 表达式;所有样式需内联或通过@page { margin: 2cm; }控制
Puppeteer 中需显式启用 printBackground 和 displayHeaderFooter
很多人写了 @page 却没显示页码,根本原因是 Puppeteer 默认禁用页眉页脚渲染。即使 CSS 正确,也必须传参开启:
await page.pdf({
path: 'output.pdf',
format: 'A4',
displayHeaderFooter: true,
printBackground: true,
headerTemplate: '',
footerTemplate: '第 页'
});
-
displayHeaderFooter: true是硬性前提,否则@page中的@top/@bottom完全不生效 -
footerTemplate和headerTemplate是字符串 HTML,其中class="pageNumber"和class="totalPages"会被 Puppeteer 自动替换(仅限这两个 class 名) -
printBackground: true确保背景色、边框等正常输出,否则页脚可能空白
页码起始值与分节控制要用 counter-reset 和 counter-increment
封面、目录、正文需要不同页码格式(如封面无页码、目录用罗马数字、正文用阿拉伯数字),纯靠 @page 不够,得结合 HTML 结构和 CSS 计数器:
立即学习“前端免费学习笔记(深入)”;
body { counter-reset: page 0; }
.section-cover { counter-reset: page; }
.section-toc { counter-reset: page; }
.section-main { counter-reset: page 1; }
@page {
@bottom-center {
content: counter(page, decimal);
}
}
.section-toc::before {
counter-increment: page;
content: "";
}
-
counter-reset: page N重置页码计数器,N是起始值(0表示第一页显示为 1) - 必须配合
counter-increment: page才能推进计数,否则页码始终为重置值 - 分节页码在 WeasyPrint 中效果稳定;Puppeteer 的
footerTemplate不支持动态计数器,只能靠服务端预生成 HTML 分节
displayHeaderFooter: true 这个开关,以及 @page 规则必须放在顶层 CSS(不能套在 .container 里),否则整段规则静默失效。











