canvas在高分屏下模糊的根本原因是物理像素不足,解决方案是按设备像素比(dpr)放大canvas.width/height,用css固定显示尺寸,并调用ctx.scale(dpr, dpr)保持绘图逻辑不变,同时动态监听dpr变化并重绘。

Canvas在高分辨率屏幕(如Retina屏、Windows高缩放比显示器)下模糊,不是画得不够细,而是画布的物理像素数量跟不上显示需求。核心解决思路是:让Canvas内部缓冲区覆盖足够多的物理像素,再用CSS“压回”设计尺寸,最后用ctx.scale()保持绘图逻辑不变。
按设备像素比放大画布尺寸
浏览器通过window.devicePixelRatio(简称dpr)告知当前1个CSS像素对应几个物理像素。常见值为2(MacBook)、3(高端手机)、1.25或1.5(Windows系统缩放)。必须用它来重设Canvas的width和height属性:
- 先获取Canvas在页面中的实际CSS尺寸,推荐用
getBoundingClientRect(),避免硬编码或依赖offsetWidth - 设置
canvas.width = rect.width * dpr、canvas.height = rect.height * dpr - 同时用CSS固定视觉大小:
canvas.style.width = rect.width + "px"、canvas.style.height = rect.height + "px"
必须调用ctx.scale(dpr, dpr)
只放大width/height会让所有绘图坐标自动“变小”——比如想画一个40×30像素的按钮,实际只占40/dpr × 30/dpr物理像素,几乎看不见。因此绘制前务必执行:
生成Claude风格的精美单页HTML汇报文件。当用户需要生成"汇报"、"周报"、"月报"、"项目进度"、"复盘"、"演示"、"slide deck"、"状态报告"、"工作总结"时触发。支持6种模板:周报(weekly)、项目进度(project)、月度总结(monthly)、复盘报告(postmortem)、演示文稿(slid
-
ctx.scale(dpr, dpr),此后所有坐标(fillRect、arc、drawImage等)仍按CSS像素书写 - 文字和线宽也要同步放大:
ctx.font = "14px sans-serif"→ 改为ctx.font = (14 * dpr) + "px sans-serif" -
ctx.lineWidth = 1→ 改为ctx.lineWidth = 1 * dpr
响应设备变化,避免静态假设
dpr不是一成不变的。用户切换显示器、调整系统缩放、甚至iOS Safari地址栏收起都可能触发变化。仅监听resize远远不够:
- 用
window.matchMedia(`screen and (min-resolution: ${dpr}dppx)`)创建媒体查询对象 - 监听其
change事件,在回调中重新计算尺寸、清空画布、重设scale、重绘 - 加简单防抖(如150ms),防止频繁重绘影响性能
- 复杂场景可先用
canvas.toDataURL()暂存画面,减少闪烁;静态内容建议用离屏Canvas预渲染
避开几个典型错误
很多模糊问题其实来自误操作:
- ❌ 只改
style.width/style.height却不改width/height属性——等于强制拉伸低分图 - ❌ 调用
scale(dpr, dpr)后,仍用物理像素坐标绘图(例如传fillRect(0,0,2,2))——应始终按CSS逻辑像素写 - ❌ 在
scale()之后又用CSStransform: scale()缩放Canvas——双重缩放破坏像素对齐 - ❌ 忽略抗锯齿影响:对文字或精细图形,可临时关闭:
ctx.imageSmoothingEnabled = false,并确保坐标取整(如Math.round(x))
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










