用 window.devicePixelRatio 取整动态加载 CSS 比 @media 更可靠,因媒体查询仅控制规则生效而非资源加载,存在匹配粗糙、兼容性差、无法精准按 DPR 加载等问题;JS 方案可精确加载对应 DPR 文件,需取整兜底、路径规范、内联执行,并注意与 lib-flexible 冲突。

直接用 window.devicePixelRatio 取整后动态加载 CSS 文件,比纯 CSS 媒体查询更可靠、更可控。
为什么 @media (min-device-pixel-ratio: 2) 不够用
这类媒体查询本质是“条件启用”,不是“条件加载”。它只能控制已引入的 CSS 规则是否生效,无法触发新资源下载。实际项目中容易遇到这些问题:
-
min-device-pixel-ratio: 2会同时匹配 DPR=2 和 DPR=3 的设备,没法做精细区分 - 部分安卓 WebView(尤其旧版)对
-webkit-min-device-pixel-ratio返回0或undefined,而window.devicePixelRatio更稳定 - 横竖屏切换、缩放操作后,DPR 实际未变,但某些浏览器媒体查询会误判或不重触发
- 把所有 DPR 的样式塞进一个文件,白占带宽——DPR=1 的用户也得下 3x 图背景和 0.333 缩放边框规则
怎么用 JS 动态加载对应 DPR 的 CSS
核心逻辑简单:取整、拼路径、插入 <link>。关键在细节处理:
- 取整用
Math.round(),不是Math.floor()或parseInt();DPR=2.75 应归为 3,不是 2 - 兜底写法:
const dpr = Math.min(3, Math.round(window.devicePixelRatio || 1)),避免极端值干扰 - 文件名统一用整数后缀,如
base-dpr1.css、base-dpr2.css、base-dpr3.css,别用dpr2.5.css - 必须放在
最顶部的内联<script></script>中执行,否则页面可能先按默认 DPR 渲染再闪动 - 禁止用
fetch+innerHTML注入样式 —— 会破坏 CSSOM,且浏览器预加载器无法识别
和 lib-flexible 共存时要注意什么
如果项目里还残留 lib-flexible,它的 data-dpr 属性和字体缩放逻辑容易和你新加载的 DPR CSS 冲突:
立即学习“前端免费学习笔记(深入)”;
- 优先注释掉
lib-flexible中设置font-size的那行(通常是docEl.style.fontSize = ...),只保留data-dpr属性注入 - 这样你可以继续用
[data-dpr="2"]做局部微调,又不会和全局字体缩放打架 - 若必须保留其缩放能力(比如依赖它解决 1px 边框),那你加载的 DPR CSS 就不该再设
font-size或border,专注处理background-image、box-shadow、图标等不受缩放影响的属性
真正难的不是识别 DPR,而是让不同 DPR 下的像素级渲染结果一致。比如 0.5px 边框在 Safari 支持良好,但在某些安卓 WebView 里仍会四舍五入成 1px —— 这时候光靠 CSS 媒体查询或 JS 加载都救不了,得换伪元素 + transform: scaleY() 这类兜底方案。


















