Flying Saucer 生成 PDF 时正文与页脚重叠,如何解决?
应将页脚放在 @page 的底部页边距区域,并用 margin-bottom 预留空间。根据现有代码,重叠主要是因为 .footer 使用了 position: fixed,正文分页时不会自动为页脚留出位置。
Flying Saucer 支持用于页眉、页脚的 margin boxes 和 running elements。可以用 position: running(...) 配合 content: element(...) 实现重复页脚。Flying Saucer 用户指南
为什么给 body 增加底部空白没有解决问题?
body 是跨页的文档元素。给它设置底部 margin 或 padding,不能代替为每页正文区域设置底部页边距。因此,padding-bottom: 60mm 可能只在文档末尾增加空白,正文仍可能进入固定页脚所在的区域。Flying Saucer 的指南也区分了 body 边距与 @page 页边距。分页与页边距说明
移除 position: fixed 后,页脚会回到普通文档流,跟在全部正文之后,因此只在最后一页出现。这与描述中的现象一致。
1. 把页脚模板放到正文之前
将主模板调整为:
{{footer}}
{{table}}
<div class="disclaimer-section">
<ul>
{{disclaimer}}
</ul>
</div>
{{footer}} 仍然展开为原来的 <div class="footer">...</div>,内部表格不需要重写。把 running element 放在正文之前,可以让第一页布局时取得页脚内容,避免它直到文档末尾才被定义。
2. 用页边距区域承载页脚
删除原来的 .footer 固定定位规则,以及 @media print 中重新设置固定定位的规则,再加入以下 CSS:
@page {
margin: 15mm 12mm 40mm 12mm;
@bottom-center {
content: element(pdfFooter);
vertical-align: top;
}
}
body {
margin: 0;
padding: 0;
font-family: "Microsoft JhengHei";
font-size: 10px;
color: #333;
line-height: 1.4;
}
.footer {
position: running(pdfFooter);
width: 100%;
font-size: 8pt;
line-height: 1.4;
background-color: transparent;
}
.footer-remark {
margin: 0 0 4px 0;
text-align: left;
font-size: 8pt;
}
.footer-table,
.footer-right-table {
width: 100%;
border-collapse: collapse;
}
.page-counter::before {
content: counter(page) " / " counter(pages);
}
pdfFooter 是自定义名称,running(pdfFooter) 与 element(pdfFooter) 必须一致。其余页脚单元格样式可以保留。
示例中的 40mm 是底部页边距的起始配置,并非根据现有材料测得的页脚高度。应根据实际页脚高度和所需间隔调整,尤其要考虑 {{footerRemark}} 换行后占用的空间。vertical-align: top 让页脚从底部页边距区域的上端开始排列。如果需要额外间隔,可以给 .footer 增加适量的 padding-top,并把它计入预留高度。
3. 清理合并后的 CSS 覆盖
这些 HTML、CSS 片段拼入同一个文档后,选择器会共同参与样式计算。表格片段中的 *、body 规则并不只作用于正文表格。
建议把字体和正文基础样式集中到主模板,表格片段只保留 .projection-table 及其后代选择器。重点检查最终样式中是否还存在:
.footer { position: fixed; },包括@media print中的规则。- 原来用于补偿页脚的
body底部margin、padding。 - 其他
@page规则覆盖了底部页边距。
还要检查模板替换后的完整 XHTML。原始主 CSS 中出现了 {{table}};如果它实际被替换成 HTML 表格,就不应放在 <style> 内。如果它代表 CSS 片段,需要确认替换结果是有效 CSS。
表格的 page-break-inside 应该怎样处理?
page-break-inside: avoid 控制元素是否允许在内部分页,不负责给页脚预留空间。不要依靠给整张长表格设置它来解决重叠;表格超过一页时,避免分页的要求本身就无法满足。Flying Saucer 会放弃无法满足的分页约束。分页行为说明
如果还需要尽量避免单行被拆开,可以单独尝试:
table.projection-table tr {
page-break-inside: avoid;
}
这仍然以单行能够放进一页的正文区域为前提。
如何确认调整有效?
用足以生成多页的表格和实际可能出现的较长 footerRemark 生成 PDF,检查第一页、中间页和最后一页,确认页脚重复显示、正文在底部页边距之前结束,且页码和总页数正确。
原问题没有提供 Flying Saucer 版本、最终拼装后的 XHTML 或可查看的重叠图片,因此无法确认是否还有其他样式影响。如果调整后仍然重叠,应先核对上述规则是否实际生效,再检查页脚是否高于预留的底部页边距。
备注:内容仅供参考。
