修好糟糕的打印:为任何网站定制一个 @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-inside、break-before 和 break-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 里把它整合起来
- 创建一条规则,限定到你经常打印的那个站点 —— 例如
https://docs.example.com/*。 - 把全部六个块粘进 CSS 面板,包在一个
@media print里(或保持各自分开 —— 两种都行)。 - 打开页面,按 Ctrl+P,看预览。迭代:任何仍然不对的就加一个选择器。
- 同步你的密钥,让同一套干净的打印设置跟着你到每一台设备。
因为整个东西都在 @media print 里,你可以让规则永久启用。它在正常浏览时休眠,只在你打印或导出 PDF 时才醒来。
值得知道的陷阱
- 背景图形开关 —— Chrome 的打印对话框有一个「背景图形」复选框,会覆盖你的一些颜色选择。你的
!important规则对前景仍然取胜,但两种状态都测。 - 固定/粘性元素在某些浏览器里会在每一打印页上重复。如果一个页眉一直冒出来,在打印块里给它设
position: static !important。 - 生成的 URL 可能换行得很糟 —— 这就是我们加
word-break: break-all的原因;没有它,一个长 URL 会把布局挤歪。 - 别隐藏太多 —— 图注、图片署名和作者署名是内容,不是外壳。隐藏列表要写得具体。
另见
- 一个响应式调试浮层 —— 在布局问题进到打印件之前就发现它们。
- 把页面复制为干净的 Markdown —— 从凌乱的页面取出内容的另一种方式。
一个好的打印样式表是一次性的、十五分钟的活儿,而它在你每一次保存 PDF 时都有回报。安装 JustZix,给你最常打印的站点限定一条规则,再也不与打印预览搏斗。
为这篇文章评分
暂无评分 — 成为第一个。