← 全部文章

教程

修好糟糕的打印:为任何网站定制一个 @media print 样式表

你在一篇长文上按下 Ctrl+P,预览却是一场灾难:导航栏吃掉了第一页,侧边栏盖住了文字,一个 cookie 栏漂在第三段上面,一片纯深色背景正要榨干你的打印机墨盒。这个网站从来没写过打印样式表。那就自己写一个 —— 它活在一条 JustZix CSS 规则里,让「另存为 PDF」重新可用。

为什么大多数网站打印效果糟糕

打印是 web 开发中最被忽视的部分。设计师在屏幕上测试;QA 在屏幕上测试;没人打开打印预览。结果是,网络上很大一部分要么根本没有 @media print 块,要么有一个多年前写的、早已不再匹配布局的。于是浏览器原样打印屏幕布局 —— 固定页眉、多列网格、深色主题,全都打出来。

修法是一条只在页面被打印时才生效的 CSS 规则。@media print { ... } 里的一切在屏幕上不可见,只在纸张和 PDF 导出时启动。这意味着你可以很激进:隐藏整片区域、给一切重新上色、强制单列 —— 这些都不会触碰正常浏览。

第 1 步 —— 隐藏一切非内容

导航、侧边栏、页脚、分享小部件、cookie 栏、粘性的「订阅」框:这些都不该出现在纸上。先隐藏那些显而易见的外壳。

@media print {
  header, nav, aside, footer,
  .sidebar, .site-header, .site-footer,
  .cookie-banner, .newsletter, .share-bar,
  .ad, [class*="advert" i], [id*="cookie" i],
  [role="banner"], [role="navigation"],
  [aria-label*="cookie" i] {
    display: none !important;
  }
}

如果页面仍然打印出垃圾,打开打印预览,在 DevTools 里找到那个碍事的块,把它的选择器加进列表。每个站点你只需做一次 —— 规则会被保存。

第 2 步 —— 展开被截断的内容

许多网站把文字钳制到几行、隐藏溢出,或把文章放进一个固定高度的滚动框里。在屏幕上这没问题;在纸上它会把你的内容切掉。把钳制撤销。

@media print {
  /* Kill height limits and scroll boxes */
  main, article, .content, .post-body {
    height: auto !important;
    max-height: none !important;
    overflow: visible !important;
  }

  /* Undo line-clamp truncation */
  * {
    -webkit-line-clamp: unset !important;
    overflow: visible !important;
  }

  /* Force the article full width, drop the grid */
  body, main, article {
    display: block !important;
    width: 100% !important;
    max-width: 100% !important;
    margin: 0 !important;
    float: none !important;
  }
}

* 一刀切地用 overflow: visible 看起来很粗暴,但在 @media print 里这正是你想要的 —— 打印件上不应该有任何东西被裁切。

第 3 步 —— 控制分页

对一份打印件的最大单项改进,是阻止东西在元素中间跨页断开。一个代码块被拆到两张纸上、一个标题孤零零地留在页底、一个表格行被撕成两半 —— 这些都能用碎片化属性修好。

@media print {
  /* Never split these across a page */
  pre, blockquote, table, figure, img,
  li, .card {
    break-inside: avoid;
  }

  /* Keep a heading with the text that follows it */
  h1, h2, h3, h4 {
    break-after: avoid;
  }

  /* Start each top-level section on a fresh page */
  .chapter, section.page {
    break-before: page;
  }
}

现代属性是 break-insidebreak-beforebreak-after。老的 page-break-* 名字仍然有效,Chrome 会自动映射它们,但新规则就写新的。

第 4 步 —— 在锚点后显示链接 URL

一个打印出来的链接毫无用处 —— 读者没法点击「点这里」。用一个生成内容的技巧,把实际的 URL 打印在它旁边。

@media print {
  a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 0.85em;
    color: #555;
    word-break: break-all;
  }

  /* Don't print URLs for in-page anchors or javascript: links */
  a[href^="#"]::after,
  a[href^="javascript:"]::after {
    content: "";
  }
}

这会把 href 属性拉进可见文字里。如果太吵,就给页内锚点链接和图片链接跳过它 —— 一份满是长长追踪 URL 的打印件本身就是另一种乱。

第 5 步 —— 用 @page 设置页边距

@page 规则控制打印纸张本身:它的页边距和尺寸。浏览器也允许你在打印对话框里设置页边距,但把它们烤进规则里意味着那个站点的每一次打印都一致。

@media print {
  @page {
    margin: 18mm 16mm;
    size: A4;
  }

  /* Tighter margin on the first page if you have a title block */
  @page :first {
    margin-top: 12mm;
  }
}

第 6 步 —— 强制浅色背景以节省墨水

深色主题的网站打印出来是一片墨粉墙。默认情况下 Chrome 打印时会去掉背景色(除非勾选了「背景图形」),但文字常常仍是浅灰色,因为它假设有一个深色背景。强制一个干净的黑底白字 —— 黑字白底。

@media print {
  html, body, * {
    background: #fff !important;
    background-image: none !important;
    color: #000 !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }

  /* Keep images and real photos intact */
  img, svg, video { filter: none !important; }

  /* Slightly soften secondary text so it still reads as secondary */
  .muted, .meta, time, small { color: #444 !important; }
}

这保证了无论站点主题如何,输出都可读、省墨 —— 而且它与在打印对话框里关掉「背景图形」配合得很好。

在 JustZix 里把它整合起来

  1. 创建一条规则,限定到你经常打印的那个站点 —— 例如 https://docs.example.com/*
  2. 把全部六个块粘进 CSS 面板,包在一个 @media print 里(或保持各自分开 —— 两种都行)。
  3. 打开页面,按 Ctrl+P,看预览。迭代:任何仍然不对的就加一个选择器。
  4. 同步你的密钥,让同一套干净的打印设置跟着你到每一台设备。

因为整个东西都在 @media print 里,你可以让规则永久启用。它在正常浏览时休眠,只在你打印或导出 PDF 时才醒来。

值得知道的陷阱

另见

一个好的打印样式表是一次性的、十五分钟的活儿,而它在你每一次保存 PDF 时都有回报。安装 JustZix,给你最常打印的站点限定一条规则,再也不与打印预览搏斗。

为这篇文章评分

暂无评分 — 成为第一个。

自己动手试试

安装 JustZix,粘贴本文中的任意代码片段。两分钟,从零到一条在你所有设备上生效的规则。

获取 JustZix

功能 · 工作原理 · 示例 · 应用场景