搜索全站
主题 12 分钟阅读

WordPress主题打印样式:print.css制作打印友好文章页

客户打印文章页后拿到十几页广告和黑色背景,多半是主题没写打印样式。本文讲清 @media print 的工作方式,给出一份可直接放进主题的 print.css,并说明链接地址展开、分页控制与页眉页脚的处理办法。

U
UFO_PF 2021-03-04 · 阅读 12 分钟
Wo 主题
阅读提示
本文约 4,768 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:打印出来二十页,有用的只有三段

做技术博客的人多少遇到过这种反馈:读者把教程打印出来贴在工位,结果发现打印稿里夹着侧边栏推荐、相关文章卡片、评论框、深色背景整块黑底,一份 1500 字的文章打印了 9 页,其中 6 页是导航和广告。更糟的是打印稿里所有超链接都变成普通黑色文字,读者想按链接找原文根本找不到。

打印样式(print stylesheet)是被绝大多数商业主题忽略的一环。原因不难理解:它不影响任何线上指标,无法在 Google Analytics 里体现价值,所以几乎没有主题把它列入卖点。但对于教程站、文档站、外贸站的产品规格页,打印是真实存在的场景——客户会把规格参数打印给采购,读者会把步骤打印出来照着操作。把它做成「所见即所得的一页纸」,是低成本但感知很强的一件事。

原理分析:@media print 到底改变了什么

浏览器打印时切换的是媒体类型 print。此时有几条与屏幕完全不同的规则:

特性 屏幕(screen) 打印(print)
背景色/背景图 正常渲染 默认不打印(省墨设置)
单位建议 px / rem pt / mm / cm
分页 不存在 由 break-* 属性控制
绝对定位元素 正常 常被截断或跑到页外
白色文字 正常 白底上看不见
链接 有 hover / 下划线 全部失去交互,看不出是链接

其中最致命的两条是:深色主题在打印时会把深底丢掉、留下浅色文字,直接变成一片空白;以及链接失去可辨识性。@media print 的作用就是在打印这一刻把这两类问题覆盖掉。

加载方式上,WordPress 主题里有两种写法:单独一个 print.css 用 wp_enqueue_style() 注册时指定 media => 'print';或者直接写进主样式表的 @media print {} 块。前者的好处是可以被缓存策略单独处理,也便于子主题整份替换;后者少一个请求。这里用独立文件方案,因为它天然支持子主题覆盖。

保姆级实操

步骤 1:在主题里准备文件

在主题(或子主题)根目录建 print.css,与 style.css 平级。

步骤 2:只在打印媒体下加载

<?php
/**
 * 加载打印样式,media 指定为 print,不影响屏幕渲染性能
 */
add_action( 'wp_enqueue_scripts', 'mimangfei_print_styles' );
function mimangfei_print_styles() {
    wp_enqueue_style(
        'mimangfei-print',
        get_stylesheet_directory_uri() . '/print.css',
        array(),
        wp_get_theme()->get( 'Version' ),
        'print'
    );
}

wp_enqueue_style() 的第五个参数就是 media,传 'print' 后浏览器会把它标记为打印专用,屏幕渲染时不参与 CSSOM 阻塞,对首屏没有任何开销。

步骤 3:写 print.css 主体

@page {
  size: A4;
  margin: 16mm 14mm;
}

@media print {
  /* 隐藏一切与正文无关的区域 */
  .site-header .banner,
  .site-navigation,
  .widget-area,
  .sidebar,
  .comments-area,
  .related-posts,
  .post-navigation,
  .site-footer,
  .wp-block-buttons,
  .sharedaddy,
  .ad-slot,
  .breadcrumb { display: none !important; }

  /* 容器归零,避免残留外边距 */
  body,
  .site-content,
  .entry-content {
    margin: 0 !important;
    padding: 0 !important;
    width: auto !important;
    max-width: none !important;
    float: none !important;
  }

  /* 强制可读的前景色,杜绝白字白底 */
  body, p, li, td, th, blockquote {
    color: #000 !important;
    background: transparent !important;
    font-size: 11pt;
    line-height: 1.5;
  }

  h1 { font-size: 20pt; }
  h2 { font-size: 16pt; }
  h3 { font-size: 13pt; }

  /* 标题不被拆到上一页末尾 */
  h1, h2, h3, h4 { break-after: avoid; page-break-after: avoid; }
  img, table, pre, figure { break-inside: avoid; page-break-inside: avoid; }
  p, li { orphans: 3; widows: 3; }

  /* 图片自适应纸宽 */
  img { max-width: 100% !important; height: auto !important; }
}

步骤 4:把链接地址打印出来

这是打印样式里最容易被忽略、也最有用的一条:

@media print {
  /* 正文内的外部链接在后面附上真实地址 */
  .entry-content a[href^="http"]::after {
    content: " (" attr(href) ")";
    font-size: 9pt;
    color: #444;
    word-break: break-all;
  }

  /* 站内锚点与图片链接不展开,避免刷屏 */
  .entry-content a[href^="#"]::after,
  .entry-content a[href*="wp-content/uploads"]::after {
    content: none;
  }
}

attr(href) 是 CSS2 就有的函数,兼容性极好,不需要任何 JS。第二条排除规则很重要,否则每张图片链接都会打印出一段冗长 URL。

步骤 5:加一段打印页脚

纯 CSS 无法拿到文章标题,需要服务端配合,用 wp_head 注入一个只在打印时显示的元素:

<?php
add_action( 'wp_head', 'mimangfei_print_footer' );
function mimangfei_print_footer() {
    if ( ! is_singular( 'post' ) ) {
        return;
    }
    $title = esc_html( get_the_title() );
    $url   = esc_url( get_permalink() );
    echo '<div class="print-only-footer">' . $title . ' — ' . $url . '</div>';
}
.print-only-footer { display: none; }

@media print {
  .print-only-footer {
    display: block;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    font-size: 9pt;
    color: #666;
    border-top: 1px solid #ccc;
    padding-top: 4pt;
  }
}

position: fixed 在分页打印时行为因浏览器而异,Chrome 会只在第一页底部渲染一次,这已经足够起到溯源作用。

步骤 6:验证

Chrome 打开任意文章页 → Ctrl+P,在打印预览里逐项检查:页数是否落在合理区间、有没有黑块、链接是否带地址、表格是否被拦腰截断。Firefox 的打印预览对 break-inside 支持更严格,建议两个都过一遍。

常见踩坑

  1. 只在 @media print 里写 display:none,忘了重置宽度:侧边栏消失后主内容仍带着 max-width: 720px,右半张纸留白。必须同时把 width / max-width 归零。
  2. 深色主题打印出黑块:即便设了 background: transparent,若主题用 filter: invert() 或 mix-blend-mode 处理深色模式,打印时依然会出问题,需要在打印块里显式 filter: none。
  3. !important 加得不够:主题样式表优先级可能更高,尤其是用 :where() 之外的块样式。打印样式要靠 !important 兜底。
  4. 背景图二维码消失:打印时背景图默认不输出,不要把二维码做成 background-image,用 <img> 标签。
  5. 案例: 某文档站给 pre 代码块加了 overflow-x: auto,打印时横向溢出的代码被直接裁掉右半行,读者照着抄命令全是错的。修法是打印态下改为 overflow-x: visible; white-space: pre-wrap; word-break: break-all;,宁可换行也不能裁切。
  6. 强制分页用 page-break-before: always 写在每个 h2 上:会让一页只放一个小节,纸张浪费严重。正确做法是只在 h1 或明确的章节容器上用。
  7. 忘了 print 媒体参数:wp_enqueue_style() 不传第五个参数时默认 all,打印样式会参与屏幕渲染,其中的 !important 可能污染前台。

总结

一份合格的打印样式,判断标准就三条:打印页数与正文长度相称(1500 字文章应落在 2–3 页)、页面上没有任何深色块或空白区域、所有外部链接都带有可见地址。做到这三条,打印稿就能直接用。

实施成本很低,一个 60 行左右的 print.css 加 10 行 PHP 注册代码即可覆盖绝大多数主题。优先级上,教程/文档/产品规格类站点值得做,纯资讯站可以只做隐藏侧边栏和链接展开两项最小改动。若你还想顺带优化打印时的图片体积,可以参考 主题加载的资源请求数精简清单;打印样式本身不参与屏幕渲染,因此与 WordPress主题性能优化的度量方式 里的首屏指标互不干扰。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。