Html 页面打印时无法自定义 Margin 修改边距

为了实现 HTML 页面打印成 PDF 的功能,在后端使用 Playwright 调用浏览器进行打印,在开发中发现,不论怎么修改 margin 参数,页面始终没有变化。

经过一翻排查,发现是 @page css 规则限制了的原因。

正文

后端通过 python 微服务调用 playwright 打印模块,实现将 html 转换成 pdf,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
async def print_html_to_pdf_bytes(html_content, print_options: dict = {}) -> bytes:
"""
将 HTML 内容渲染并返回 PDF 的二进制数据。
pdf_options 常用选项,参考 page.pdf 的参数
注意:page.pdf 仅在 Chromium 可用。
"""
async with await allocate_page() as page:
await page.set_content(html_content, wait_until="load")

try:
# 当不传递 path 参数时,page.pdf 会返回 PDF 的二进制数据
pdf_bytes = await page.pdf(
**{
**{
"format": "A4",
"print_background": True,
"display_header_footer": True, # 必需:启用页眉/页脚占位符替换
},
**print_options,
}
)
except Exception as e:
# 抛出更友好的提示(例如在非 Chromium 环境)
raise RuntimeError(
"生成 PDF 时出错(注意:page.pdf 仅在 Chromium 中受支持)。原始错误: "
+ str(e)
)
finally:
pass

return pdf_bytes

其中,print_options 的值为:

1
2
3
4
5
6
7
8
{
"margin":{
"top": "20mm",
"right": "10mm",
"bottom": "10mm",
"left": "10mm"
}
}

这段代码在打印某个 html 页面时,始终无法修改打印后的边距,在网上搜索 playwright margin 相关的问题,github 上 issues 中显示这个 bug 早已经修复了。

最后,猜测可能是 html 本身有问题,打开 html 文件查看,发现 css 中存在以下内容:

1
2
3
4
5
6
7
8
9
@page {
size: A4 portrait;
margin-left: 20mm;
margin-right: 10mm;
margin-top: 10mm;
margin-bottom: 10mm;
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}

原因终于明了了,@page 规则是一种 CSS 规则,用于修改打印页面的不同方面。它的目标是修改页面的尺寸、方向和页边距。

它的存在,会覆盖浏览器本身的 margin 打印设置,因此一直无法生效。

参考

  1. [BUG] Controlling margins when making a PDF using Playwright - Margins don't respect CSS · Issue #3434 · microsoft/playwright

  2. @page - CSS:层叠样式表 | MDN