CSS3输出PDF打印的小技巧

CSS3输出PDF打印的小技巧

前文再续,书接上一回,自从《PHP输出PDF打印HTML5+CSS3打印格式控制》之后,实现了用HTML5+CSS3直接输出成PDF文件,以满足各种奇葩的打印格式需求。这个的确给调试打印打来了各种便利,不过随着深入使用,也碰到一些个小问题。

Linux系统没有中文字体

其实这个是前文忘记交代的问题。把系统部署到Linux的时候就发生了,不过这个问题其实比较好解决,直接在服务器安装文泉驿的开源中文字体即可。ubunutu服务器直接:

apt-get install ttf-wqy-zenhei

在打印CSS中,修改如下:

@page {  size: A4;  margin: 12mm 10mm;  padding: 0;  font-family: "Wenquanyi Micro Hei", "Microsoft YaHei", Simsun, sans-serif;  font-size: 10pt;}

对,加个字体生命即可,是不是很简单呢?

Prince和wkhtmltopdf这两个引擎,从本质上说,就是一个浏览器引擎,当然他们有比较特殊的渲染机制,尤其是实现CSS3标准的特性,并且他们可以将结果输出到PDF文件流。

为啥要引入这个东东呢,主要的问题在于,目前主流的浏览器,在对打印部分的CSS3标准支持的还很有限。就算我针对性的做出html的打印样式,但客户的打印格式,肯定会存在一些比较特殊的要求。除此之外,直接打印html还存在一些不稳定、不确定的地方,需要有前端的经验去进行“特制”,但这就导致了可能为了实现一个需求而进行特制,但下次就忘记了,或者要教会别的人也学会这种“特殊”方法,可能也花不少时间。所以相对而言,采用CSS3,传统html,不需要额外学习什么东西,同时,输出成PDF,输出的内容也相当的稳定。

非标准纸张的针打纸张尺寸设置

针打纸张的尺寸比较特殊,非标准印刷纸张。但使用Chrome浏览器对PDF文件打印输出的时候,老版本的Chrome纸张尺寸只有几个标准的纸张尺寸,这问题也困扰了我一段时期。

国内外似乎对这个问题,也没有比较深入一点资料。不过后来无意中更新了Chrome到56版本,发现Chrome已经支持在选择打印机的时候,自动识别打印机里面设置的特殊纸张格式,你可以在选择了打印机以后,找到这个特殊的纸张格式。

所以,你要做的只有两件事:

1. 在打印机首选项里面,添加你的针打纸张尺寸,多数针打都支持:

2. 在Chrome(具体是什么版本支持的,我没去细究了)打印的时候,选好对应的打印机:

至此,整个ERP系统的所有打印需求都已满足了,合同、发票、出入库单、送货单、物料编码不干胶。

下一阶段,打算基于nw.js或者Electron.js,将整个客户端打包,主要是想通过客户端发起webscoekt来实现实时的消息推送,如果基于浏览器窗口的话,不好管理webscoekt客户端连接数。

除此之外,因为已经完全是纯JS前端的APP应用了,单个窗体过程,存在一个数据对象太多的问题。因为整个界面都是无刷新的,所以各种类型的数据获取以后,靠客户端的窗口进程来维持着大量的数据对象,Chrome也是有极限的。一些不常更新的数据,其实可以作为本地持久化保存的方案进行处理。

CSS3控制打印的小技巧

回到正题了,其实CSS3控制打印,也没有什么特别神秘的东西。

基础的技巧,我就不说了,可以直接看这篇教程《Designing For Print With CSS》,老外介绍的很详细了。

因为在调试的时候,可以直接用html预览基本效果,所以调试过程也相当的轻松。不过有几点值得注意的:

1. 在打印调试的时候,使用mm或者cm,比较易于控制实际的打印效果,px时不太适合的。

2. em、rem属性同样适用于打印的样式,他们真的很方便,非常符合设计要求。

3. 字体使用pt单位。字号和具体的mm尺寸转换表(原谅我图找得有点崩):

4. 最后的最后,奇淫巧技时间到。就算利用到了CSS3、输出到PDF,但是客户的打印需求可能还是存在一些比较特殊的情况,这里还是就要利用table来实现。

有个这样的需求:

送货单的样式,页头有送货单抬头、客户信息、送货信息、付款说明等,内容部分是一个Table,里面是送货单的明细,页脚附有一段说明文字,之后是签名栏。

当Table的明细内容超多的时候,要展现到第二页(这不是废话吗,还有第三、四、五等等),但是要求Table表头能在每一页都展现。

同时,第二页也要求有页头、页脚(也就是重复出现)。

最终的打印输出结果要求如下图:

首先,重复表头,我们并不需要分隔输出这个Table,只要利用CSS3的特性即可:

table {page-break-inside: auto}tr {page-break-inside: avoid;page-break-after: auto}thead {display: table-header-group}tfoot {display: table-footer-group}

其次,对于页头、页脚的多页展现。虽然在@page,支持有@top-center、@bottom-center等,允许你设置具体的方位上的页头页脚内容,比如:

@page {@top-left {content: "手写单号#<?php echo $deliveryCode; ?>";}@top-right {content: "<?php echo $delivery->code; ?>";}}

但是显然,这种方式并不支持设置包含html的内容,虽然你可以通过css控制他们的位置,宽度等。所以需要放一些包含html标签的内容的画,我们就需要考虑用别的办法了,那么到底是什么办法呢?其实什么特别的都不用做,只要利用回上述的table部分的样式即可,也就是说,直接利用css控制table的thead和tfoot的重复渲染特性来实现。

所以,我们又回到了table布局的年代:

<table border="0" width="100%" cellpadding="0" cellspacing="0"><thead><tr><td >页头</td></tr></thead><tbody><tr><td >明细</td></tr></tbody><tfoot><tr><td >页脚</td></tr></tfoot></table>

就这样,你只要将具体内容,放入delivery-tbody中即可完成整个需求,很简单,对不对?

推荐阅读