canvas高清渲染需同步控制三要素:canvas.width/height(乘dpr)、css宽高(保持设计尺寸)、ctx.scale(dpr,dpr),缺一不可;否则将导致模糊、坐标错位、文字发虚。

关键不是“用不用 scale”,而是让 ctx.scale 和 CSS 尺寸、canvas 内在尺寸三者严格对齐。否则容易出现模糊、坐标错位、文字发虚等问题。
必须同步设置 canvas 的三个维度
高清屏渲染清晰的核心,是让每个 CSS 像素由整数个物理像素承载。这需要同时控制:
-
canvas.width / height 属性:决定缓冲区物理像素数量,要乘以
window.devicePixelRatio - CSS width / height 样式:决定画布在页面中占多少视觉空间,保持设计尺寸(如 100% 容器宽高)
- ctx.scale(dpr, dpr):告诉绘图上下文“我现在画的 1 单位,实际占 dpr 个物理像素”,使 fillRect(0,0,10,10) 仍精准覆盖 10×10 CSS 像素区域
标准初始化流程(含防错细节)
每次重设画布(比如 resize 或 DPR 变化时),都应执行以下步骤:
- 用
getBoundingClientRect()获取当前 CSS 尺寸(比 clientWidth 更可靠,不受 transform 影响) - 计算并赋值:
canvas.width = rect.width * dpr,canvas.height = rect.height * dpr - 用 CSS 固定显示尺寸:
canvas.style.width = rect.width + "px",canvas.style.height = rect.height + "px" - 获取 ctx 后立即重置并缩放:
ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.scale(dpr, dpr);(setTransform防止多次缩放叠加) - 调用
ctx.clearRect(0, 0, canvas.width, canvas.height)清空旧缓冲区
缩放后绘图要注意哪些细节
启用 ctx.scale(dpr, dpr) 后,所有绘图操作仍按 CSS 逻辑像素写坐标,但部分样式需显式适配:
-
字体大小:原
ctx.font = "14px sans-serif"→ 改为ctx.font = (14 * dpr) + "px sans-serif",否则文字会变细发虚 -
线宽:原
ctx.lineWidth = 1→ 改为ctx.lineWidth = 1 * dpr,才能保证 1 物理像素粗细 -
鼠标/触摸点映射:事件坐标需反向除以 dpr:
ctx.isPointInPath(x / dpr, y / dpr) - 阴影、虚线等:所有依赖像素精度的样式,只要视觉上要求“1px 效果”,就应乘以 dpr
响应设备变化不能只靠 resize
DPR 可能在插拔显示器、iOS 地址栏收起、系统缩放调整时动态变化,仅监听 window.resize 不够:
- 用
window.matchMedia(`screen and (min-resolution: ${dpr}dppx)`)创建媒体查询对象 - 监听其
change事件,在回调中触发重设流程 - 加简单防抖(如 200ms),避免连续触发导致卡顿或闪烁
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











