学完这篇,你能用纯 CSS 把网页的打印/导出 PDF 效果收拾干净:去掉导航和广告、控制分页、补全链接地址、避免表格和图片被拦腰截断。
第一步:把打印样式单独隔离出来
所有打印规则都写进 @media print,桌面样式写进 @media screen,互不干扰。
@media print {
/* 打印专用样式写这里 */
}
如果规则较多,也可以单独放一个文件,用 media 属性声明它只管打印:
<link rel="stylesheet" href="/css/print.css" media="print">
调试不用真打纸。Chrome 按 F12 → 右上角三个点 → More tools → Rendering → 找到 Emulate CSS media type,选 print,页面立刻变成打印视图;也可以直接 Ctrl+P 看预览,但预览里的分页更接近真实结果,建议两个都用。
第二步:重置打印基础样式
打印机默认不打印背景色和背景图(除非用户在打印对话框勾了"背景图形"),所以别用背景色传递信息(比如用浅黄底表示"重点"),要改成加粗或边框。
@media print {
* {
background: transparent !important;
color: #000 !important;
box-shadow: none !important;
text-shadow: none !important;
}
body {
font-family: "Songti SC", SimSun, serif;
font-size: 12pt;
line-height: 1.6;
}
a { color: #000; text-decoration: underline; }
a[href^="http"]::after {
content: " (" attr(href) ")";
font-size: 9pt;
color: #555;
word-break: break-all;
}
}
注意:a::after 一定要加 [href^="http"] 限定,否则锚点链接(#section)和 javascript: 链接也会被展开成一串没用的字符。
第三步:用 @page 控制纸张和页边距
@page {
size: A4;
margin: 18mm 16mm;
}
@page :first {
margin-top: 25mm;
}
size 还可以写 A4 landscape(横向)、letter。论文、合同这类正式文档建议留足 16–20mm 边距,否则装订侧会被裁掉字。
注意:想在 @page 里用 @bottom-center { content: counter(page) } 加页码,目前 Chrome / Edge 不支持(这是 Paged Media 的一部分,只有部分排版引擎实现)。要页码,最省事的办法是在打印对话框里勾选"页眉和页脚",或者后端生成 PDF 时加。
第四步:隐藏交互元素,展开被折叠的内容
@media print {
nav, .sidebar, .ad, .comment-form, .back-to-top,
.share, .toolbar, .toc, footer { display: none !important; }
main, .content { width: 100% !important; margin: 0 !important; float: none !important; }
/* 折叠的正文要自动展开,不然打印出来是空的 */
.collapse, details { display: block !important; height: auto !important; overflow: visible !important; }
details > summary { display: none; }
}
注意:隐藏元素请用 display: none,不要用 visibility: hidden 或 opacity: 0——后两者元素仍然占据版面,会留下一大片空白。
第五步:分页控制,别让标题孤零零留在页底
@media print {
h1, h2, h3 { break-after: avoid; page-break-after: avoid; }
p, li { orphans: 3; widows: 3; }
.chapter { break-before: page; }
img, table, pre, blockquote, figure {
break-inside: avoid;
page-break-inside: avoid;
}
}
orphans / widows 控制段落至少留几行在页底/页首,防止一个字单独占一行。break-after: avoid 让标题后面至少跟一段正文,避免"标题在页底、内容在下一页"。
注意:break-inside: avoid 对一个比整页还高的元素是无效的,浏览器只能硬切。所以别把整章内容包在一个 div 上设 avoid,只对图片、小表格、代码块这类"小整块"使用。
第六步:表格、图片、代码块的收尾细节
@media print {
table { width: 100%; border-collapse: collapse; font-size: 10pt; }
thead { display: table-header-group; } /* 跨页时表头重复 */
tr { break-inside: avoid; }
th, td { border: 1px solid #999; padding: 4px 6px; }
img { max-width: 100% !important; height: auto !important; }
pre {
white-space: pre-wrap;
word-break: break-all;
border: 1px solid #ccc;
padding: 8px;
font-size: 10pt;
}
}
thead { display: table-header-group } 是长表格打印的关键,跨页时每页都会自动带上表头,否则第二页开始的表格就"没头没脑"。
第七步:让打印页眉显示文章标题
浏览器打印页眉默认显示网页的 <title>。如果站点标题很长(像"某某网 - 首页"),可以在打印前临时替换:
let oldTitle;
window.addEventListener('beforeprint', () => {
oldTitle = document.title;
document.title = document.querySelector('h1')?.innerText || oldTitle;
});
window.addEventListener('afterprint', () => {
document.title = oldTitle;
});
把这段放进公共 JS 即可,对"打印这篇文章"这类场景效果明显。
小结
- 所有打印样式放
@media print,用 DevTools 的 Rendering 面板模拟媒介调试,不用真打印。
- 先做重置:去背景、统一黑字、字号用
pt,链接用 a[href^="http"]::after 补全网址。
@page 管纸张与页边距;页码在浏览器端靠打印对话框,别指望 CSS 计数器。
- 隐藏用
display: none,折叠内容要主动展开,主内容区宽度重置为 100%。
- 分页三件套:标题
break-after: avoid、小块元素 break-inside: avoid、长表格 thead { display: table-header-group }。