核心是统一坐标系、锁定整数落点、选用清晰字体并关闭插值:需按 DPR 缩放 canvas 物理尺寸与绘图上下文,文字坐标取 Math.round(),字体声明完整且禁用 imageSmoothing。

核心是统一坐标系、锁定整数落点、选用清晰字体,并关闭干扰渲染的插值行为。不处理设备像素比(DPR)时,文字常落在半像素位置,触发抗锯齿导致毛边;而单纯放大 canvas 尺寸却不缩放绘图上下文,又会让 fillText 坐标错位,进一步加剧虚影。
正确设置 canvas 物理尺寸与缩放
必须同步调整 canvas 的内部像素尺寸和绘图坐标系:
- 获取当前 DPR:
const dpr = window.devicePixelRatio || 1 - 设 canvas.width/height 为
clientWidth * dpr和clientHeight * dpr(物理像素) - 立即调用
ctx.scale(dpr, dpr),使后续所有 x/y 坐标仍按 CSS 像素书写,逻辑不变 - 确保
canvas.style.width和style.height保持原始 CSS 值(如 "400px"),不可省略或写成百分比
强制文字落在像素中心
即使缩放后,动态计算的坐标仍可能含小数。对关键文字需做整数对齐:
- 水平居中时用
ctx.textAlign = "center",x 取Math.round(containerWidth / 2) - 垂直居中推荐
ctx.textBaseline = "middle",y 取Math.round(containerHeight / 2) - 避免直接传入浮点 y(如 100.3),一律用
Math.round(y)再传给 fillText
优化字体与渲染策略
字体本身和浏览器渲染开关也直接影响清晰度:
立即学习“前端免费学习笔记(深入)”;
- font 字符串必须完整,优先用无衬线体:例如
"bold 16px -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" - 中文加回退链:
"15px 'PingFang SC', 'Microsoft YaHei', sans-serif",避免单写 SimSun 等缺失字体 - 关闭图像插值(对文字有间接改善):
ctx.imageSmoothingEnabled = false - 给 canvas 元素加 CSS:
image-rendering: pixelated; -webkit-backface-visibility: hidden;
不推荐的“伪解决”做法
这些方式看似简单,实则引入新问题:
- 只改 canvas.style.transform: scale(2) —— 触发浏览器二次缩放,必然模糊
- 手动把 fillText 的 x/y 乘以 dpr,却不调用 ctx.scale —— 坐标系混乱,baseline 错位
- 依赖 maxWidth 自动换行 —— 实际是强制缩放整段文本,导致字形变形发虚
- 用 ctx.font = "12px serif" 这类极简写法 —— 回退到默认 10px sans-serif,字号失控易糊



















