解决 PDF 表格内容溢出:jquick-pdf 最大宽高配置
引入
传统方案里限制 PDF 内容尺寸,往往要在写出之前手工裁剪文本或重算布局,业务描述一变长就得重排。jquick-pdf 在样式模型中提供 width、height、minWidth、minHeight、maxWidth、maxHeight,用声明式属性约束元素盒子,布局交给引擎。但这带来一个高频误解:盒子被限制,不等于文本被截断。本文以 OverflowDemo 说明 maxWidth、maxHeight 的真实语义、超长文本的实际表现,以及业务层需要如何配合。
环境基线为 io.github.paohaijiao:jquick-pdfx:4.1.0 与 JDK 8+。
核心讲解
尺寸上限约束的是盒子
README 与渲染测试已验证驼峰与连字符写法互为别名:maxWidth/max-width、maxHeight/max-height。它们限制的是元素盒子尺寸的上限。渲染器不会因为你设了 maxHeight 就把超出部分删除或自动加省略号,文本仍按正常排版规则换行,只是容器不再继续增高。因此“设了上限就安全”是错的。
完整示例:OverflowDemo
import com.github.paohaijiao.executor.JQuickPdfFactory; // 导入工厂
import java.nio.file.*; // 导入文件工具
public class OverflowDemo {
// 声明类
public static void main(String[] args) throws Exception {
// 声明入口
String template = "<pdf><body><h1>'尺寸保护'</h1>" // 创建模板
+ "<div style=\"width:460px;maxWidth:460px;maxHeight:180px;border:1px solid #555;padding:8px\">" // 设置宽高上限
+ "<p>'这是一个较长的说明文本,用于观察内容换行和最大高度配置。请在生产环境先限制输入长度。'</p>" // 添加测试文本
+ "</div></body></pdf>"; // 结束模板
byte[] pdf = new JQuickPdfFactory().executeContent(template); // 渲染模板
Files.write(Paths.get("overflow-safe.pdf"), pdf); // 保存 PDF
}
}
效果
单位换算与盒子占用
px 按 96 DPI 换算,1px 等于 0.75pt,所以示例中的 460px 约等于 345pt,180px 约等于 135pt。估算可用宽度时还要扣除元素的 padding 与 border:div 设了 padding:8px,内容区宽度是 460px 减去左右各 8px;border:1px solid #555 的写法是「类型 宽度 颜色」,会让盒子外沿比内容区更宽。页面尺寸或边距调整后,这些数值必须整体复核,否则会出现“明明设了 maxWidth 还是贴边”的现象。
限制盒子仍然有价值
即使不会截断文本,maxWidth、maxHeight 依然有实际作用:阻止异常长的单行把整张表的列宽撑变形、阻止某个块无限增高挤掉后续内容的分页余量,让版面在不同数据下保持可预期。正确的分工是——样式属性负责盒子尺寸,业务代码负责文本长度与拆分策略。
执行步骤
估算页面可用宽度 → 设置 maxWidth → 限制高度 → 对超长输入在业务层分页或截断 → 回归测试。
长内容拆块示例
与其把长文本塞进一个受高度上限约束的盒子,更稳妥的方式是在业务层先切块,每块单独受限,块之间自然衔接:
import com.github.paohaijiao.executor.JQuickPdfFactory; // 导入工厂
import java.nio.file.*; // 导入文件工具
String longText = "业务长文本……"; // 待输出的长内容
int step = 120; // 每块字符数
StringBuilder blocks = new StringBuilder(); // 块缓冲
for (int i = 0; i < longText.length(); i += step) {
// 按固定长度切块
blocks.append("<div style=\"maxWidth:460px;margin-bottom:6px\">") // 每块独立受限
.append("<p>'").append(longText.substring(i, Math.min(longText.length(), i + step))).append("'</p>") // 块内容
.append("</div>"); // 结束块
}
byte[] pdf = new JQuickPdfFactory().executeContent("<pdf><body>" + blocks + "</body></pdf>"); // 渲染
Files.write(Paths.get("overflow-split.pdf"), pdf); // 保存
每块高度由内容决定,不再需要 maxHeight 兜底;顺序与换行都交给引擎,适合把超长备注铺满整页的场景。切块粒度是取舍点:块越大版面越整齐、跨页越少,块越小越容易塞进页面剩余空间。
关键细节
- 只约束盒子:
maxHeight到达上限后内容可能溢出或被裁切,具体表现必须在目标阅读器里确认,不能假设文本完整可见。 - 超长文本:没有空格的长串(URL、哈希、连续数字)缺少换行点,最容易横向溢出,需要
maxWidth配合业务层插入分隔,或在入库前限制输入长度。 - 单位换算:px 按 96 DPI 处理(1px = 0.75pt)。页面尺寸或内边距变化后,硬编码的 px 上限要重新核对。
- 上下限组合:
minWidth、minHeight同样在样式模型中,可与上限搭配使用;驼峰或连字符写法都需保持团队规范统一。 - 与
keepTogether的取舍:keepTogether让块尽量不被跨页拆开,maxHeight限制块的高度上限;同时使用时要保证“被保护的块”仍能放进一页,否则整块会被推到下一页,甚至出现反复尝试分页的情况。若块本身接近整页高度,应优先保证可读性,放弃keepTogether。
常见溢出形态与对应处理
- 横向溢出:文字或 URL 超出右边界,用
maxWidth固定块或列宽,并在业务层插入可换行分隔。 - 纵向溢出:内容超过盒子高度被切,不要只提高
maxHeight,先判断这些内容是否真的该塞进一个盒子。 - 表格整体超宽:把各列宽度之和收敛到页面可用宽度,并给最右列留出内边距。
- 固定高度导致重叠:检查是否给行或块写死了过小的
height,长说明会与相邻内容挤在一起。
实战说明
验证步骤
- 用
div设置width:460px、maxWidth:460px、maxHeight:180px,加边框与padding:8px(见上方代码)。 - 先放入一句短文本,确认盒子实际宽高与边框、内边距符合预期。
- 把文本换成远超 180px 高度的长文本,观察容器高度是否停在 180px、文本是否换行、是否被切。
- 文本长度逐步加倍,记录第几倍时出现可见问题,作为业务层截断阈值的参考。
- 切换两种页面尺寸各跑一次,确认宽度上限在不同页宽下都不会贴边。
结果预期
- 外层块宽度不超过 460px,高度不超过 180px。
- 短文本完整可见;超长文本是否完整可见必须结合具体阅读器确认。
- 若文本被裁切,说明仅靠样式属性不足以解决问题,必须由业务层参与。
排查顺序
- 先看块宽是否超过页面可用宽度减去
padding、border。 - 再看高度上限是否小于最少内容所需高度;单行文本都放不下时,裁切几乎必然发生。
- 把文本替换为一句短文本复测,区分“内容过长”与“盒子过小”。
- 最后做阅读器一致性确认:同一份 PDF 在目标阅读器里再看一次。
业务层配合方式
- 截断:在传入模板前按字符数截断并追加省略号。
- 省略:保留首尾关键字段,把中间长内容替换为固定文案。
- 分页:把长内容拆到多个块或多页,必要时用
areaBreak强制分页,而不是把压力全交给maxHeight。 - 表格长字段:优先用
maxWidth固定列宽让单元格换行,再对极端值做业务层截断。
生产注意事项
- 不能把
maxHeight当作文本截断 API。 - 长内容应拆分为多块或在业务层分页。
- 页面尺寸变化时要留出内边距,并重新核对 px 单位换算。
- 适用于备注卡片、异常说明、表格长字段保护等场景。
总结
- 本文的关键结论:
maxWidth、maxHeight约束元素盒子,超限不会自动截断或加省略号,文本可见性由渲染换行与阅读器共同决定。 - 适用边界与常见误区:把
maxHeight当截断开关、用固定 px 硬编码页面尺寸、在大块上同时叠加keepTogether与贴近整页高度的上限,都会带来不可预期的版面。 - 尺寸属性负责约束盒子,数据策略负责约束文本,两者配合才能真正解决溢出。本文版本基线:jquick-pdfx 4.0.0、JDK 8+,升级前请核对 README_zh.md 的版本对照表;更多示例见 GitHub 仓库。