根本原因是@media print未进入打印解析流程或被高权重屏幕样式覆盖:link必须显式设media="print",@import须置于css最顶部,且需用cmd+p真实预览验证,禁用懒加载与通配符重置,提升选择器权重或加!important。

根本原因不是选择器写错了,而是它压根没进打印样式解析流程,或者被更高权重的屏幕样式盖掉了。
为什么 @media print 里的选择器完全不触发
Safari 和 Chrome 对 @media print 的加载逻辑极其苛刻:如果 <link> 标签没带 media="print",浏览器可能直接跳过整张样式表(哪怕里面写了 @media print)。@import 更危险——必须放在 CSS 文件最顶部,写在 @media print { } 里面等于白写。
- 检查最终 HTML 源码,确认
<link rel="stylesheet" media="print" href="print.css">真实存在且返回 200 - 用 DevTools → Network 面板过滤
print.css,看是否加载成功;若被构建工具懒加载(如 Vite 的import()动态引入),它大概率不会进打印上下文 - 别把打印样式混在主样式表里,尤其当它被 Bootstrap 或 Tailwind 这类框架 CSS 覆盖时,
@media print块会被静默忽略
.header { display: none; } 在 Safari 打印预览里还显示?
这不是语法问题,是特异性(specificity)被碾压了。比如 Bootstrap 的 .navbar.navbar-light 带 !important,你的单类名规则根本抢不过。
- 用 DevTools → Elements → 选中元素 → Styles 面板,看
display值到底来自哪条规则(注意筛选 “print” 媒体) - 提升权重:改用
body .header、div#app .header,或加!important(Safari print 场景下,这是务实选择,不是妥协) - 避免通配符重置:
* { display: none; }在 Safari 中可能部分失效或引发分页异常,逐个写关键类更稳
JS 动态插入的 .modal 或 .toast 打印时还在页面上
CSS 是静态匹配的,它不等 JS 渲染。你写的 .modal { display: none; } 只对初始 DOM 生效;JS 插入后,若没重新计算样式或没覆盖新节点,就漏掉了。
- 在
@media print里显式声明:.modal, .toast, .loading, .dropdown-menu { display: none !important; } - 如果用了 Vue/React 条件渲染(如
v-if或{show && <div classname="modal">}),确保这些类名在打印时真实存在于 DOM 中(可 Cmd+P 后右键“查看页面源代码”确认)<li>Shadow DOM 内部元素需用 <code>::slotted(.item)或:host .inner,普通选择器无效 - 背景图和颜色:Chrome 默认关掉“背景图形”,必须手动勾选;Safari 则需加
color-adjust: exact !important;强制输出 - 浮动和定位:统一重置
* { float: none !important; position: static !important; },否则float: left的导航栏可能卡在页眉中间不动 - Flex/Grid 容器:打印时强制退化为块级,
.container { display: block !important; }比猜它怎么换行更可靠 - 表格分页:给
<thead> 加 <code>display: table-header-group;,给<tr> 加 <code>page-break-inside: avoid;,但前提是父<table> 没设 <code>overflow: hidden真正难搞的从来不是写规则,而是发现某个
position: sticky的页眉在打印时卡在中间一页不动——它既没被display: none干掉,也没触发任何break规则,得手动加position: static !important;才能解决。
字体、背景、浮动导致打印布局塌陷或空白页
打印引擎对 CSS 的支持远弱于屏幕渲染,很多属性默认被禁用或行为异常。











