Canvas文字高分屏模糊主因是dpr未对齐导致坐标偏移和亚像素渲染;解法是用dpr放大canvas物理尺寸并调用ctx.scale(dpr,dpr)校准坐标系,使绘图逻辑与CSS像素一致。

Canvas 文字在高分屏上模糊,不是字体问题,而是设备像素比(dpr)没对齐导致的坐标偏移和亚像素渲染。核心解法是让绘图坐标系与 CSS 视觉尺寸严格匹配——用 dpr 放大 canvas 物理尺寸,再用 ctx.scale(dpr, dpr) 把绘图逻辑拉回“写多少 CSS 像素就画多少”的直觉状态。
获取并应用设备像素比
先读取当前设备的真实缩放比例,这是所有适配的前提:
-
const dpr = window.devicePixelRatio || 1;—— 必须在初始化 canvas 时立即获取,不能缓存,因为用户可能动态切换显示器或缩放系统设置 - 用
getBoundingClientRect()获取 canvas 的实际显示尺寸(避免 offsetWidth 受 margin/padding 干扰) - 设置 canvas 的物理宽高:
canvas.width = rect.width * dpr;和canvas.height = rect.height * dpr; - 同步设置样式宽高,保持视觉大小不变:
canvas.style.width = rect.width + "px";、canvas.style.height = rect.height + "px";
重置绘图上下文坐标系
仅放大 canvas 尺寸还不够,此时 ctx 的 (0,0) 到 (100,100) 实际覆盖了 200×200 物理像素(dpr=2),直接 fillText 会严重偏移。必须校准坐标系:
- 调用
ctx.scale(dpr, dpr);后,所有后续绘制命令(包括fillText)的 x/y 参数仍按 CSS 像素理解,比如fillText("A", 100, 50)就真画在容器水平 100px、垂直 50px 的位置 - 不要手动把文字坐标乘以 dpr,那会造成双重缩放;也不要用 translate 或半像素偏移去“微调”,那是旧思路,已失效
- 确保
scale在每次重绘前只调用一次,避免叠加缩放
文字对齐与抗锯齿优化
坐标系对齐后,文字基线和清晰度才可控:
- 水平居中:设
ctx.textAlign = "center",再传入 CSS 宽度一半的 x 值(如rect.width / 2) - 垂直居中:设
ctx.textBaseline = "middle",y 值取 CSS 高度一半(如rect.height / 2),避开 alphabetic 基线漂移 - 强制整数落点:关键文字建议用
Math.round(x)和Math.round(y),杜绝小数坐标引发的亚像素模糊 - 字体选型:优先用系统清晰字体,例如
ctx.font = "bold 16px -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",避免 Times New Roman 等易糊衬线体
响应式兜底处理
用户拖动窗口跨显示器、系统缩放变更时,dpr 可能突变,需监听并重建:
- 监听
window.onresize和window.matchMedia("(resolution)").addEventListener(部分浏览器支持) - 更稳妥做法:在每次绘制前检查
window.devicePixelRatio !== currentDpr,若变化则重新 setupCanvas 并清空重绘 - 避免频繁重建 canvas 元素,优先复用并重设 width/height + scale
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











