使用flying-saucer-pdf-itext5转PDF时格式异常、CSS不生效问题
我来帮你排查下这个问题——用Flying Saucer转HTML到PDF时格式跑偏、CSS不生效是挺常见的坑,咱们一步步来分析可能的原因和解决办法:
1. XHTML转换过程可能破坏了原结构
你用Tidy把HTML转成XHTML,但Tidy的自动修复逻辑可能会修改原HTML的结构:比如自动闭合未闭合的标签、合并冗余标签,甚至可能误删某些class或style属性。这些改动都会导致原CSS选择器失效,布局走样。
解决办法:
转换后打印或保存生成的XHTML内容,对比原HTML检查结构是否一致:
String xHtml = convertToXhtml(htmlContent); // 打印XHTML内容排查结构问题 System.out.println(xHtml); // 或者写入文件方便查看 Files.write(Paths.get("output.xhtml"), xHtml.getBytes(StandardCharsets.UTF_8));
如果发现Tidy修改了关键结构,可以调整Tidy的配置,比如关闭自动合并标签、保留原属性:
tidy.setForceTags(false); // 不强制修改标签 tidy.setPreserveEntities(true); // 保留实体 tidy.setMakeClean(false); // 不清理冗余内容
2. Flying Saucer对CSS的支持有限
Flying Saucer基于CSS 2.1规范,对很多现代CSS特性(比如Flexbox、Grid、CSS3伪类/属性)支持不足甚至完全不支持。如果你的原HTML用了这些特性,转PDF时就会出现格式失效的情况。
解决办法:
- 检查你的CSS代码,替换掉Flying Saucer不支持的特性:比如用
float布局替代Flexbox,用表格布局实现复杂排版(虽然复古但兼容性好)。 - 确认所用CSS属性都在Flying Saucer的兼容范围内。
3. 外部资源(CSS/字体/图片)加载失败
如果原HTML引用了外部CSS文件,用renderer.setDocumentFromString(xHtml)时,Flying Saucer不知道这些资源的基路径,会导致CSS加载失败,自然无法渲染正确格式。
解决办法:
- 把CSS内联到HTML的
<style>标签中,确保样式直接嵌入XHTML。 - 或者设置基URL,让Flying Saucer能找到外部资源:
// 假设CSS文件在项目的src/main/resources/css目录下 String baseUrl = Thread.currentThread().getContextClassLoader().getResource("css").toURI().toString(); renderer.setDocumentFromString(xHtml, baseUrl);
4. 字体未正确注册
如果你的HTML用了非系统默认字体(比如宋体、微软雅黑),Flying Saucer默认不会加载这些字体,会用替代字体渲染,导致文字大小、行高、排版出现变化。
解决办法:
手动注册需要的字体:
// 注册自定义字体(比如宋体),路径根据实际情况调整 renderer.getFontResolver().addFont("fonts/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // 在CSS中指定字体 // body { font-family: "SimSun"; }
5. 缩放设置影响布局
你使用了renderer.setScaleToFit(true),这个设置会让PDF内容自适应页面宽度,可能导致元素被拉伸或压缩,破坏原布局。
解决办法:
尝试去掉这个设置,改用固定缩放比例:
// 去掉setScaleToFit // renderer.setScaleToFit(true); // 设置固定缩放(1.0为原尺寸) renderer.setZoom(1.0);
额外注意事项
确保你的XHTML是严格符合规范的:所有标签闭合、属性用引号包裹、嵌套结构正确。Flying Saucer对XHTML语法要求很严格,哪怕一个未闭合的标签都可能导致整个布局失效。
内容的提问来源于stack exchange,提问作者Anonymous

