唯一可靠方案是使用@page + counter(page),因其由浏览器原生计数器驱动,不依赖js、不触发重排,且被chrome/edge/firefox/puppeteer/wkhtmltopdf等主流引擎支持。

浏览器打印时显示的“第 X 页”不是网页 DOM 的一部分,不能靠 innerHTML 或 textContent 直接写进去;真正在打印输出中生效的页码,必须用 CSS @page 规则配合 counter(page),且仅对物理分页起作用。
为什么 window.print() 后看不到你写的“第2页”文字
你在页面里放一个 <div>第2页</div>,打印预览里大概率不会出现在每一页右下角——因为浏览器把打印内容按纸张尺寸重新排版、分页,你的 DOM 元素只属于某一页的内容流,不会自动复制到每一页。而浏览器 UI 自带的“第 1 页 / 共 5 页”是渲染层叠加的,开发者无法控制或覆盖。
- 所有手动插入的页码文本(如
<span class="print-page">第 <span id="pageNum">1</span> 页</span>)在打印时会被固定在原始位置,不会随分页重复出现 -
window.print()不提供回调或钩子来动态注入页码,JS 在打印触发后即暂停执行 - 试图用
document.fonts.load()+ 高度测量 + 手动切<section></section>再塞页码,只适用于高度严格可控的 PDF 导出场景,普通打印极易错位
@page + counter(page) 是唯一可靠方案
这是目前所有主流打印引擎(Chrome、Edge、Firefox、Puppeteer、wkhtmltopdf)都支持的语义化方式,不依赖 JS,不触发重排,页码由浏览器原生计数器驱动。
- 必须写在
@media print外层,不能嵌套在其他选择器里:@page { @bottom-center { content: "第 " counter(page) " 页"; } } -
counter(page)是只读内置变量,不能counter-reset: page 5起始偏移(Chrome/Edge 不支持,Firefox 有限支持但不可靠) - 位置关键词严格区分大小写:
@bottom-center✅,@bottomcenter❌,@bottom-center在 Chrome 115+ 才稳定支持 - 如果要加总页数,
counter(pages)可用,但需搭配@page :first { @bottom-center { content: "第 " counter(page) " 页 / 共 " counter(pages) " 页"; } },且仅首页生效
Puppeteer 生成 PDF 时页码不显示?检查 displayHeaderFooter
很多人写了正确的 @page 却导出 PDF 没页码,根本原因是 Puppeteer 默认关闭页眉页脚渲染。
- 必须显式传参:
displayHeaderFooter: true,否则@page中的@top/@bottom完全不生效 -
printBackground: true要同时开启,否则页脚背景色、边框可能空白 - 不要混用
footerTemplate和@page:Puppeteer 的footerTemplate是字符串 HTML,会覆盖@page设置;若要用,只能写成footerTemplate: '<div style="font-size:12px;text-align:center;">第 <span class="pageNumber"></span> 页</div>',其中class="pageNumber"会被自动替换为当前页码 -
@page { margin: 20mm; }只影响内容区边距,不影响页眉页脚区域高度;页脚高度需靠footerTemplate内容撑开或设置margin-bottom
打印时想隐藏浏览器默认页眉页脚?用户侧无法自动关闭
Chrome/Edge 打印对话框里的「页眉和页脚」勾选项,JS 无法通过 window.print() 自动取消——这是浏览器安全策略限制,防止网页静默污染打印输出。
- 能做的只有 CSS 尝试压制:
@page { margin: 0; }缩小内容区边距,但对系统级页眉页脚无效 - 部分旧版 wkhtmltopdf 支持
--no-pdf-compression --margin-top 0参数绕过,但现代工具链已弃用 - 真实交付场景中,应在打印按钮旁加小字提示:“打印前请在对话框中取消勾选『页眉和页脚』”
- 如果必须完全控制,放弃
window.print(),改用 Puppeteer 后端生成 PDF 并提供下载链接
真正难的不是写出那行 @page { @bottom-center { content: "第 " counter(page) " 页"; } },而是确保它在整个打印流程中不被 CSS 层叠覆盖、不因字体加载延迟错位、不因用户缩放比例失效——这些细节在测试阶段最容易被忽略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











