高清屏下Canvas布局错乱主因是绘图坐标系与物理像素未对齐,需同步更新canvas尺寸、重置ctx.scale(dpr,dpr)并监听devicePixelRatio变化,三步缺一不可。

高清屏下 Canvas 缩放后布局错乱,核心不是“画得不准”,而是绘图坐标系和物理像素没对齐——重设 canvas.width/height 会清空状态(包括 ctx.scale),导致缩放归零,所有坐标偏移。解决关键在于:同步更新尺寸、重置缩放、监听设备变化。
Canvas 尺寸与缩放必须成对操作
只改 CSS 宽高或只放大 width/height 都不行,必须三步一起做:
- 用
canvas.clientWidth和clientHeight获取当前显示尺寸(CSS 像素) - 乘以
window.devicePixelRatio设置canvas.width和canvas.height - 立即调用
ctx.scale(dpr, dpr),让绘图坐标回归逻辑像素单位
漏掉第三步,你画 fillRect(10, 10, 20, 20) 实际只占 5×5 物理像素,在 DPR=2 屏上几乎看不见。
避免重设 canvas.width 触发状态重置
常见错误:canvas.width = canvas.width 或在 resize 中无条件重赋值——这会让 ctx 的缩放、线条宽度、字体大小等全部回到初始值(scale=1)。
- 只在
dpr变化或容器尺寸真正改变时才重设宽高 - 重设后必须立刻补上
ctx.scale(dpr, dpr),不能依赖之前的状态 - 如果用了自定义坐标系(如地图投影),缩放后还需重新设置 transform 或调整绘图逻辑
监听设备像素比动态变化
用户切显示器、系统缩放调整、浏览器窗口拖到外接屏时,resize 事件不触发,但 devicePixelRatio 已变。
- 用
matchMedia('(resolution)')监听分辨率变化(兼容 Chrome/Firefox/Safari) - 初始化和 media 查询回调里都执行一次
resizeCanvas() - 不要只在页面加载时读一次
dpr,它不是静态常量
地图类应用额外注意瓦片匹配
Canvas 是载体,地图内容本身也要适配高清:
- Leaflet 必须开启
detectRetina: true,否则永远请求 256×256 普清瓦片 - 瓦片 URL 要支持
@2x后缀,或用{r}占位符由库自动注入 - Cesium/Deck.gl 等 WebGL 地图,除了 canvas 重设,还要调用
gl.viewport()和setProps({width, height})更新渲染上下文
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











