作为一只深度“网瘾少年”,偶尔看到喜欢的网页内容,除了会选择使用笔记工具收藏、浏览器收藏夹库加star外,偶尔还会使用纸质打印保存,或者使用浏览器提供的网页转PDF功能留个备份。

然而提到打印,多数网页并不是都适合打印的。

打印网页结果和传统书籍的异同

两者相同点挺多,但简而言之:

基本都是图文混排的平面“图像”。

最关键的差异点:

网页中呈现的内容和最后想打印的结果可能差异很大,屏幕尺寸和要打印的纸之间的比例不同,网页中有大量的不需要打印的元素,甚至如果直接在打印机上预览页面,页面脚本可能无法正确的被执行(前端模版方案包含的页面内容可能被忽略掉)。

解决方案

  • 优选使用CSS提供的@media规则来针对特定设备来展示内容。
  • 次选使用JS来针对设备、屏幕宽度、UA来进行内容渲染和展示。
  • 在实现页面内容呈现的过程中,HTML结构中最大程度只保留页面必要内容。

CSS Media Query

这个方案实际上是相对比较稳健的,IE从6.0支持all, print, screen这三种基本的屏幕类型的样式的加载(link tag),其他浏览器基本天然支持。

MDN文档中对于Media Query的语法和特性描述已经很多,这种基础的事情就不赘述了,下面聊一下怎么去更好的定义页面内的样式。

以Bootstrap为例,在v3主流版本中,它的打印机样式,主要是依赖html5-boilerplate和自己的Print utilities中的声明来实现的。

这里基本上只是简单的定义了一下规则来:去掉页面多余的颜色内容、避免自动分页、增强展示包含链接的内容。

Print utilities内容:

如果某些内容不需要展示给打印机,那么只需要添加上述类名到HTML元素上就可以了,如果页面内容是由HTML模版+JS模版实现,那么可维护性其实有一些挑战。

进阶优化

先聊针对html5-boilerplate的优化:

对于要打印的内容:

  • 进行尺寸调整,避免浪费纸张、打印结果大量留白。
  • 定义各平台默认字体,避免web-font加载失败,或者无法覆盖所有字符,打印结果混杂多种字体。
  • 针对代码标签配置等宽字体,特殊展示。
  • 差异化展示各级别标题。
  • 超链接仅展示HTTP(s)协议内容,以及图片内容,其他内容不进行展示。

针对bootstrap的优化:

  • 对于随时会更新的列表内容,默认展示一句请勿浪费纸张打印列表页面 / Don't waste paper!,避免无意义打印。
  • 对于JS模版全局生成的增强性质的节点,进行隐藏。
  • 对于sr-*阅读器相关的内容,完全不进行展示。
  • 对于页面中无法进行交互的META元素进行隐藏。

划个重点细节:

如果你把打印机样式和其他的样式都打包成一个文件,请记得取消media的设置,或者设置为all,如果像上面一样设置为screen,那么之前的工作就白费了。

或者你也可以根据设备进行样式的拆分,将打印机样式单独提取到一个地方,比如print.css,在保持之前的样式不变的情况下,使用下面的结构。

依赖JS的实现

参考detecting-print-requests-with-javascript的特性检测的方式,很容易包装一个你自己小模块。

不过这里除了可以用JS追踪用户是否进行了打印操作外,还可以稳定的添加当前设备模式的类名来给CSS进行操作举个简陋的例子:

适用场景

  • 当你无法根据上一节对link标签的media进行特殊操作的时候。
  • 当你不想大量使用Media Query能力的时候。
  • 当你的用户主流设备恰好支持JS能力比例很高的时候。

使用上面的能力检测的方式,你也会很容易做到根据打印机设备来进行内容的差异化展示了。

不过既然使用JS了,偶尔可能会有点击按钮,调出系统对话框进行打印的需求。

常规做法是:

非常规做法是:

如果在2017年你还要考虑IE678的话,那么可能你需要给页面添加一个iframe,再进行window.print()的调用了。

HTML结构优化

这个其实没有什么可说的了,记忆中有一篇老博客对这块有具体的描述,简单思路来说就是页面只展示基础的文章内容,任何修饰部分都交给JS来处理。

这样,当JS无法运行,或者运行会被阻塞的时候,页面所提供的内容依旧是完整的,并且可以大幅简化可运行JS设备的程序的复杂度,提升可维护性以及执行效率。

结束语

这套组合拳打完之后,基本你的网站就拥有了和Safari阅读模式一样的体验了,不论是直接阅读,还是打印阅读,相比较之前体验应该是有质的提升的。(可以用Safari体验一下本站 :D )

其他

  • 需要在修正网站后,补充图片对比。
  • 需要找回之前对于HTML页面结构优化的思考的文章链接。

– EOF –