canvas在高dpi屏模糊或偏移的根本原因是width/height被当物理像素而css按逻辑像素计算,必须同步三步:读取dpr、重设canvas宽高为offset×dpr、立即ctx.scale(dpr,dpr)。

怎么用 min-resolution 判断 Retina 屏才靠谱
直接写 min-resolution: 2dppx,别碰 192dpi 或单独用 -webkit-min-device-pixel-ratio: 2。前者是纯逻辑比值,1 CSS 像素对应 ≥2×2 物理像素,不依赖系统 DPI 设置或缩放比例;后者在 Windows 高缩放(比如 125%)下大概率失效,而且 Safari 16+、Chrome 110+ 已明确标记为非标准。
常见错误写法:
-
@media (min-resolution: 2dppx), (min-resolution: 192dpi)—— “或”逻辑会让非 Retina 设备意外命中192dpi,高清样式错配 -
@media (min-resolution: 2dppx, 192dpi)—— 语法非法,浏览器直接忽略整条规则
稳妥兜底写法(兼容 iOS 8–11):@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx),注意逗号分隔,不是 and 连接。
@import 加载高清 CSS 为什么总不生效
因为 @import 必须出现在 CSS 文件最顶部,不能塞进 @media 块里。下面这种写法完全无效:
@media (-webkit-min-device-pixel-ratio: 2) {
@import "high-dpi.css"; /* ❌ 浏览器直接跳过 */
}
正确姿势是把媒体条件写在 @import 语句末尾,用分号隔开:
@import "high-dpi.css" only screen and (-webkit-min-device-pixel-ratio: 2);@import "high-dpi.css" only screen and (min-resolution: 2dppx);
注意:only screen 不能省,漏掉会导致某些浏览器当成 all 类型无条件加载;路径必须用引号包裹;and 是连接词,不是逗号。
Canvas 在高 DPI 屏上模糊或偏移的根本原因
不是布局问题,是 Canvas 的 width/height 属性被当成了物理像素数,而 CSS 尺寸按逻辑像素算。当 window.devicePixelRatio > 1 时,不做处理就会拉伸模糊,或者绘图坐标整体右下偏移。
必须三步同步做:
- 读取真实 dpr:
const dpr = window.devicePixelRatio || 1,别硬写2或3 - 重设 canvas 内部尺寸:
canvas.width = canvas.offsetWidth * dpr,canvas.height = canvas.offsetHeight * dpr - 立即缩放绘图上下文:
ctx.scale(dpr, dpr),否则所有fillRect(0,0,100,100)都会错位
切记:每次 resize 后重设 width/height 会重置 ctx,scale() 必须重调;别用 transform: scale() 伪修复——事件坐标会彻底失真。
border 和 background-image 换了 @2x 图还是糊?
只换图不调尺寸,等于白换。比如 background-image: url(icon@2x.png)(200×200px),浏览器默认按 200×200 CSS 像素渲染,结果放大两倍显示,细节全丢。
关键动作是显式设回逻辑尺寸:
-
background-size: 50px 50px(假设原始逻辑尺寸是 50×50) - 边框真·1px 的稳定方案是伪元素 +
transform: scale(0.5),而不是border-width: 0.5px(iOS 8–11 不支持,安卓 WebView 多数忽略) - 伪元素需设
position: absolute、height: 1px、background-color,再加transform-origin: left bottom和-webkit-transform-origin前缀
Grid/Flex 容器本身不感知 DPI,但里面嵌的 Canvas、SVG、固定 px 字体,都得各自单独适配——父容器不会“传导”分辨率。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











