杂志

前言

有时我们有打印保存网页的需求,但对于一份静态的文档来说,原始页面的很多元素都是不必要的,如一些功能按钮和装饰元素,同时正文一般也会使用更适合印刷品的字体。
本篇文章将介绍在打印网页时如何应用不同的样式

两种方法

有两种方法可以满足我们的需求,分别为“使用媒体查询”和“使用JS辅助”

使用媒体查询

媒体查询允许针对一个特定范围的输出设备应用不同的样式,而不必改变本身的样式。在这里我们可以用媒体类型中的print来为打印机指定样式

媒体查询的最常见的用途是实现响应式设计(针对不同屏幕宽度有选择的展现不同的元素或改变页面版式而不必重新加载页面)。

媒体查询同样有两种使用方法

直接书写

在样式表中通过@media规则应用,之后的print即为说明此条@规则适用于print类型
可酌情使用!important

@media print {
    .waifu, .cPlayer, #back-to-top, .text-bar, .respond, .comment_reply, #postnav, #footer {
        display: none !important;
    }
    p, li {
        font-family: 'Source Han Serif SC','Source Han Serif','source-han-serif-sc','PT Serif','SongTi SC','MicroSoft Yahei',Source Han Sans SC,Noto Sans CJK SC,WenQuanYi Micro Hei,sans-serif !important;
        letter-spacing: normal !important;
        text-shadow: none !important;
    }
    pre {
        max-height: unset !important;
    }
}

这段样式隐藏了看板娘、播放器、回到顶部按钮、评论回复按钮、评论输入框和页脚等一些静态文档中不必要的元素或功能区域,并将正文字体更换为开源免费的思源宋体(关于如何在网页中使用思源字体留待下一篇文章再谈),同时覆盖了适合屏幕阅读的装饰用样式(字间距和文字阴影)

引入外部样式表

除此之外,媒体查询还可以在<link>标签内使用

<link rel="stylesheet" media="print" href="print.css" />

然后在print.css内书写样式即可

当媒体查询为true时(此处即为媒体类型为print),其对应的样式表或样式规则就会遵循正常的级联规则进行应用
需要注意的是,即使媒体查询返回false,<link> 标签指向的样式表也将会被下载(但是它们不会被应用)

使用JS辅助

一般情况下,媒体查询已经能够满足“在打印网页时应用不同的样式”的需求
但媒体查询应用的样式是给打印机看的,对于用户而言,并不知道页面样式发生了什么变化。同时我们可能希望在打印前执行一些代码,如添加水印或更换字体等
对于上述需求,我们可以使用类名应用样式,并使用js控制元素的类名来实现

书写样式

照常书写样式,只不过此处的选择器被加上了body.print以表示在body的类名中带有print时应用

body.print .waifu, body.print .cPlayer, body.print #back-to-top, body.print .text-bar, body.print .respond, body.print .comment_reply, body.print #postnav, body.print #footer {
    display: none !important;
}
body.print p, body.print li {
    font-family: 'Source Han Serif SC','Source Han Serif','source-han-serif-sc','PT Serif','SongTi SC','MicroSoft Yahei',Source Han Sans SC,Noto Sans CJK SC,WenQuanYi Micro Hei,sans-serif !important;
    letter-spacing: normal !important;
    text-shadow: none !important;
}
body.print pre {
    max-height: unset !important;
}

使用JS控制元素类名

beforeprintafterprint事件可以满足我们的需求,这两个事件是在HTML5中引入的

兼容性一览:

IE Edge Firefox Chrome Safari Opera
6.0 12 6 63 no 50

其中Chrome支持较晚,我们之后将使用matchMedia方法做兼容性处理

beforeprint在打印前或打印预览时触发,afterprint在打印完成或取消打印后触发,我们只需监听这两个事件,并在触发时修改body元素的类名即可

修改元素类名可以使用element.classListadd()remove()方法,十分方便。该方法支持所有现代浏览器,包括IE10+

(function(){
    //定义beforePrint方法
    var beforePrint = function() {
        document.body.classList.add('print');
    };

    //定义afterPrint方法
    var afterPrint = function() {
        document.body.classList.remove('print');
    };

    //对旧版本Chrome做兼容性处理
    if (window.matchMedia) {
        var mediaQueryList = window.matchMedia('print');

        mediaQueryList.addListener(function(mql) {
            if (mql.matches) {
                beforePrint();
            } else {
                afterPrint();
            }
        });
    }

    //分别对beforeprint和afterprint事件添加监听
    window.addEventListener("beforeprint", beforePrint);
    window.addEventListener("afterprint", afterPrint);
})();

此处仅对body元素的类名做了修改,要实现更多功能可在两个方法体中增加代码

看看效果吧

右键点击页面选择打印,或者按快捷键Ctrl+P,并打印出来(可选择输出至PDF文档)
如无意外,打印出来的文档将会使用特有的样式,如果上一步使用了js辅助的方法还可直接在浏览器窗口看到页面样式发生了变化