CSS 打印

原文链接:https://lon.im/post/css-print.html

简介

Chrome 浏览器打印预览

本文主要讲解如何使用 CSS 控制打印样式。

基本概念

使用 CSS 可以控制文档如何正确的显示在不同的媒介 (Media) 上。其中分页媒介 (Paged Media) ,不同于连续媒介 (Continuous Media),它可以控制文档内容,将其分隔至一个或多个不相关联的页面 (如:书、幻灯片)。

页面 (Page Sheet) 是物理介质 (如:纸张) 的表面,它包含可打印区域 (Printable Areas) 和不可打印区域 (Non-printable Areas)。用户代理可以调整文档内容的格式,使其显示在可打印区域。

页面打印区域和不可打印区域

页面盒子 (Page Box) 是一个由长边 (Long Edge) 和短边 (Short Edge) 组成的矩形。长边的方向决定了页面朝向 (Page Orientation),长边是垂直方向,则页面朝向为纵向 (Portrait Orientation),反之为横向 (Landscape Orientation)。

CSS 打印无法指定文档是否为双面打印 (Duplex Printing),是否双面打印应该通过用户代理指定。不管是否双面打印,CSS 打印总是包含左页和右页 (分别通过 :left, :right 指定) 。(或者说 CSS 打印假定所有文档是双面打印)

页面模型 (Page Model)

和 CSS 盒子模型一样,页面盒子模型由外边距 (margin)、边框 (border)、内边距 (padding) 和 内容区域 (content area) 构成。

页面模型

其中内容区域和外边距有着特殊的功能:

  • 内容区域也叫页面区域 (Page Area),第一页的页面区域边界构成了文档的初始的包含块 (Containing Block)
  • 页面外边距区域是透明的,环绕在页面区域周围。在 CSS3 中,可以用于创建页眉和页脚,详见下文 <a href="#page-margin-boxes">页面外边距盒子</a>

页面进度 (Page Progression)方向 是文档被分隔后的页面的排列方向。比如:现代中文页面进度多是从左至右;而古代中文的页面进度则相反。可以通过设置根元素 (root element) 的 directionwriting-mode 属性来改变页面进度。

页面的“第一页”是左页还是右页,可以由页面进度的方向决定,当页面进度方向为从左至右时,第一页是右页;反之为左页。(事实上也可以通过设置根元素的 break-before 属性来强制改变第一页是左页还是右页)

引入打印样式的三种方式

在 CSS 中使用 @media print

@media print {
    body {
        background-color: white;
    }
    img {
        visibility: hidden;
    }
    a::after {
        content: "(" attr(href) ")"; /* 所有链接后显示链接地址 */
    }
}

在 CSS 中使用 @import

@import url("my-print-style.css") print;

在 HTML 中使用 <link> 标签

<link rel="stylesheet" media="print" href="my-print-style.css">

@media print 或 my-print-style.css 中,可以自由的修改大部分样式。

使用 @page

使用打印媒介查询可以自定义很多样式,当希望改变页面大小、边距等,就需要用到 @page 了。页面上下文 (Page Context) 中仅支持部分 CSS 属性,支持的属性有:marginsizemarksbleed 以及页面外边距盒子等,不支持的属性将会被忽略。

<h4 id="page-margin-boxes">页面外边距盒子 (CSS3)</h4>

注:常见浏览器都不支持该属性,推荐使用 Prince

页面的外边距被分成了 16 个页面外边距盒子。每个外边距盒子都有自己的外边距、边框、内边距和内容区域。页面外边距盒子用于创建页眉和页脚,页眉和页脚是页面的一部分,用于补充信息,如页码或标题。

page-margin-boxes

页面外边距盒子需要在 @page 下使用,使用起来和伪类类似,也包含 content 属性。

@page {
    /* 页面内容区域底部添加一条 1px 的灰线 */
    @bottom-left, @bottom-center, @bottom-right {
        border-top: 1px solid gray;
    }

    /* 页脚中间显示格式如 "第 3 页" 的页码 */
    @bottom-center {
        content: "第" counter(page) "页";
    }
}

属性

margin (CSS2.1)

margin 系列属性(margin-topmargin-rightmargin-bottommargin-leftmargin)用于指定页面外边距大小。

在 CSS2.1 中,页面上下文中只支持 margin 系列属性。而且因为 CSS2.1 的页面上下文中没有字体的概念,margin 系列属性的值的单位不支持 emex

@page {
    size: A4 portrait;
    margin: 3.7cm 2.6cm 3.5cm; /* 国家标准公文页边距 GB/T 9704-2012 */
}
size (CSS3)

size 属性支持 autolandscapeportrait<length>{1,2}<page-size>

  • 默认值为 auto,表示页面大小和方向由用户代理决定
  • landscape 指定页面为横向,如果 <page-size> 没有指定,大小则由用户代理决定
  • portrait 指定页面为纵向,如果 <page-size> 没有指定,大小则由用户代理决定
  • <length>{1,2} 表示指定页面大小,填写两个值则分别指定页面盒子的宽度和高度,填写一个值则同时指定宽度和高度。在 CSS3 中,值的单位支持 emex,大小相对于页面上下文中字体的大小
  • <page-size> 也用于指定页面大小,等价于使用 <length>{1,2}。常用的值有:A3A4A5B4B5 等,详细尺寸请参考 ISO 216<page-size> 可以与 landscapeportrait 组合同时指定页面方向。

伪类

页面上下文也支持使用伪类,其中支持的伪类有::left:right:first:blank

伪类 :left:right

需要双面打印时,通常需要将左页和右页设置不同的样式(如页边距、页码位置)。这时左页和右页可以分别用 :left:right 表示。再次强调,通过 :left:right 设置左右页面不同样式,并不代表用户代理会将页面双面打印

/* 通过分别设置左页和右页不同的左右页面距,为装订边留出更多的空间 */

@page :left {
    margin-left: 2.5cm;
    margin-right: 2.7cm;
}

@page :right {
    margin-left: 2.7cm;
    margin-right: 2.5cm;
}
伪类 :first

伪类 :first 用于匹配到文档的第一页。

@page :first {
    margin-top: 10cm; /* 首页上页边距设置为 10cm */
}
伪类 :blank

伪类 :blank 用于匹配文档的空白页。

h1 {
    page-break-before: left; /* 一级标题强制分配到右页 */
}

@page :blank {
    @top-center {
        content: "这是空白页";
    }
}

注意,空白页既可能是左页,又可能是右页,设置左页或右页的样式也会显示在空白页上,如果不希望显示在空白页上,可以清除这些样式。

h1 {
    break-before: left;
}

@page :left {
    @left-center {
        content: "这是左页";
    }
}

@page :right {
    @right-center {
        content: "这是右页";
    }
}

@page :blank {
    @left-center, @right-center {
        content: none; /* 如果是空白页则不显示 */
    }
}

分页

page-break-beforepage-break-afterpage-break-inside (CSS 2.1)

用于控制元素之前、之后或之中是否分页,没有生成盒子的块元素不会生效

page-break-beforepage-break-after 属性支持 autoalwaysavoidleftrightrectoverso

h2 {
    page-break-before: always;
}
  • auto 默认值,表示既不强制分页也不禁止分页
  • alwaysavoid 表示在该元素之前(或之后)强制或禁止分页
  • leftright 表示在该元素之前(或之后)强制分页,使得下一页出现在左页或右页
  • rectoverso 页面进度从左至右时,分别与 rightleft 一致;反之与 leftright 一致

page-break-inside 属性仅支持 autoavoid,表示在元素内允许或禁止分页。

thead, tfoot {
    display: table-row-group;
}
thead, tfoot, tr, th, td {
    page-break-inside: avoid;
}
orphanswindows (CSS 2.1)

orphanswindows 用于指定在页面的底部或顶部,元素中允许剩余的最少行数,默认为 2 行。

最佳实践

  • “白纸黑字”--避免不必要的背景颜色、加深文字颜色等
  • 避免打印次要的内容,比如导航栏、侧边栏等
  • 链接后显示链接地址
  • 做好分页,避免标题、表格单元格等换行

示例:

@media print {
    @page {
        size: A4 portrait;
        margin: 3.7cm 2.6cm 3.5cm;
    }

    h1 {
        page-break-before: always;
    }

    h1, h2, h3, h4, h5, h6,
    thead, tfoot, tr, th, td,
    li {
        page-break-inside: avoid;
    }

    body {
        background-color: white;
        color: black;
    }

    nav, aside {
        display: none;
    }

    a::after {
        content: "(" attr(href) ")";
    }

    thead, tfoot {
        display: table-row-group;
    }
}

参考链接:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,727评论 1 92
  • 转载请声明 原文链接地址 关注公众号获取更多资讯 第一部分 HTML 第一章 职业规划和前景 职业方向规划定位...
    程序员poetry阅读 16,511评论 32 459
  • 学习CSS的最佳网站没有之一 http://www.w3school.com.cn/tags/index.asp ...
    Amyyy_阅读 1,027评论 0 1
  • •前端面试题汇总 一、HTML和CSS 21 你做的页面在哪些流览器测试过?这些浏览器的内核分别是什么? ...
    Simon_s阅读 2,219评论 0 8
  • 最可怕的事莫过于心找不到家... 我想说 这故事, 这人.. 如果:发生,相遇 不是当时的彼此 而是现在的我们 或...
    mickey早阅读 327评论 0 1