业务方上周把一份履约周报的 PDF 退回来了理由是字太小、看不清。那页报表在浏览器里是正常的46 行明细、列宽也够组里同学按 CtrlP 存成 PDF出来就是三页表格里的字缩成一团。换了个在线转换工具再导一遍这回不分页了变成很长的一页字确实大了但业务方打印出来又说纸放不下。两次都不对问题看着像是工具挑得不对。我把这件事当成一次正经的对照来跑结论和我原先的判断相反这不是工具的差别是这张网页有没有写打印 CSS 的差别。同一份 HTML不写打印 CSS 的时候两条路各按各的默认走差得很远补上打印 CSS 之后两条路的产物逐项一模一样。先说测试条件样本是我自己造的一份跨境履约周报品牌叫潮汐盒 Tidebox是编的SKU、仓库、渠道、金额全部虚构不涉及任何真实业务。页面结构就是中后台最常见的那种顶部四个指标卡下面一张 46 行的明细表表头是深色底的thead。两条路分别是浏览器自带的打印导出和图映 ImgIng一个免费的在线HTML转PDF工具的 HTML 转 PDF。跑在同一台 Mac 上、同一个 Chromium 149 内核、视口 1440×1000所以两边的排版差异不会来自浏览器版本。产物我没有靠肉眼看是用 pypdf 和 PyMuPDF 把页数、每页尺寸、表格字号、能提取到的文字数逐项量出来的。图映这条线的处理位置得单独交代被合规管着的团队尤其要看清楚。我开着 Network 面板逐条盯过一轮导入文件、读取目录、映射资源、即时预览连拿到 PDF 之后那一步无损最小化都是浏览器在本地跑完的这一整段没有任何上行。真正的那一次上行发生在点下转换之后——一份脚本已被剥掉、资源全部内联的自包含 HTML 快照经一次 POST 送到同源的 imging.cn 接口服务端的 Chromium / Skia 渲完把 PDF 回给你。它的文档能力里会出本机的就只有这一条。计数也对得上点转换之前非 GET 请求为 0点了之后恰好加一。含客户数据的报表走不走这条线得你们法务说了算别默认它是纯本地的。不写打印 CSS两条路各走各的先看那份完全没有打印 CSS 的长表。浏览器打印出来是 3 页每页 612×792pt——注意这个尺寸是 Letter不是很多人默认以为的 A4。为了把 1180px 宽的报表塞进 816pt 宽的纸Chromium 会做一次 shrink-to-fit原本 13px 的表格字被压到 6.74pt大概相当于 9px文件 431,114 字节。另一条路默认跟随页面的真实尺寸不分页也不缩放出来是 1 页 1080×2379pt表格字 9.75pt204,648 字节。字看着大是因为它根本没有缩放这一步不是渲染得更清楚——同一块区域放大了看两边的字形清晰度我没量出差别。它的代价是这一页比 A4 高出一大截直接送进打印机就是刚才业务方抱怨的那种情况。顺便纠正一个我自己也信过的说法表格行并没有被从中间切断。我给每一行埋了两处唯一标记只要同一个标记落在两页上就算切断七份样本、所有导出路径数下来都是 0 行。Chromium 这一版遇到空间不够是整行推到下一页不会把一行劈成两半。所以“表格被拦腰截断”这个锅至少在现在的浏览器上按不上去。补上三行打印 CSS两条路合流真正起作用的是这三处写法加在页面的样式里就行第一处是page声明纸张、方向和页边距比如 A4 纵向、上下左右各十几毫米。没有它分不分页、用多大的纸全由导出那一侧自己决定你在页面里怎么排都没用。第二处是给thead写display:table-header-group让表头在每一页重复。第三处是给tr写break-inside:avoid避免多行单元格从行内被断开。补齐之后再各导一遍两边都是 7 页、每页 595×842pt 的 A4、表头在 7 页上各出现一次表格字 8.25pt能提取到的文字一致率 99.32%逐项相同。到这一步用哪个工具已经不影响结果了——这就是我说的分水岭。还有个细节值得记一下page不一定要裸写在样式表顶层。我另做了一份把它放进media print{}里的对照产物和裸写那份只差 30 字节页面规格、页数、字号、文字一致率全部相同两边都认。所以不用为了它生效而破坏页面原本的样式组织。最值钱的一条别让表格待在滚动容器里这是我这轮踩到的唯一一个真正丢数据的坑也是我觉得所有做中后台的人都该看一眼的地方。我们后台的报表页表格通常是包在一个定高的滚动区里的——height:520px; overflow:autoElement UI、Ant Design 的表格组件默认就是这个形态。这样的页面导出 PDF只会保留容器里当时看得见的那一屏。我那份 46 行的表导出来只有 R01 到 R08 共 8 行剩下 38 行一条都没进 PDF能提取到的文字只剩原文的 13.40%。浏览器打印和在线转换工具在这一点上表现完全一样8 行对 8 行没有哪一边能救。更难受的是两边界面都没有任何提示进度显示正常、质量报告也写得很正常你不数行数根本发现不了。要是这份 PDF 直接发给了客户少掉的三十多行是谁也没机会发现的。躲开的办法很朴素导出之前把滚动容器还原成自然高度。可以在打印样式里写一条让那个容器的高度不限、溢出可见也可以在点导出之前用一段脚本临时改掉。我们现在是前者写进了报表页的公共打印样式省得每个人各记一遍。导出前我现在会过的几件事翻一遍页面里所有overflow:auto的容器凡是scrollHeight比clientHeight大的导出前都放开确认页面里有没有page没有就别指望导出结果听你的导出完不要只看第一页翻到最后数一下明细行数对不对得上。最后一条是如果报表带客户数据先搞清楚你用的那个工具在哪一步上传、上传了什么——前面几条挡的是返工这条挡的是事故我被法务盯过三个月所以记得特别牢。