要使Retina屏下Canvas的1px线条清晰锐利,需先按devicePixelRatio缩放canvas缓冲区并设置CSS尺寸,再将绘图坐标偏移0.5逻辑像素以对齐物理像素中心,且lineWidth设为整数1。

在 Retina 屏(或任意高 DPR 设备)下,Canvas 默认绘制的 1px 线条看起来发虚、变粗(实际占 2 物理像素),根本原因不是线宽设错了,而是 Canvas 的坐标系和像素对齐机制导致的。要让视觉上“刚好是 1 像素宽”的线条真正锐利清晰,需同时解决两个层面的问题:物理分辨率适配 + 坐标对齐。
一、先确保 Canvas 缓冲区匹配设备物理像素
这是清晰显示的前提。若跳过这步,后续所有坐标调整都只是“在模糊图像上修细节”,效果有限。
- 获取设备像素比:
const dpr = window.devicePixelRatio || 1 - 获取 Canvas 的 CSS 显示尺寸(例如 300×200 px):
const rect = canvas.getBoundingClientRect() - 设置 canvas 元素的
width和height属性为物理像素值: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);
二、让 1px 线条真正落在单个物理像素中心
即使 DPR 适配完成,若画线起点落在整数坐标(如 y = 10),Canvas 仍会以该点为中线向上下各延伸 0.5 像素——在高 DPR 下这会跨两个物理像素,触发插值模糊。正确做法是把线的中线对齐到物理像素的正中心。
- 对所有
moveTo和lineTo的坐标,手动加偏移+ 0.5(在已执行ctx.scale(dpr, dpr)的前提下,这个 0.5 是逻辑像素单位,对应 1 个物理像素的半格):ctx.moveTo(50.5, 10.5);ctx.lineTo(200.5, 10.5); - 确保
lineWidth为整数,且推荐设为1(不要用 1.2、0.8 等):ctx.lineWidth = 1; - 避免使用
strokeRect或fillRect绘制边框;改用路径 +stroke(),便于精确控制起止点
三、补充:表格/网格类场景的稳定写法
画多条等距横线/竖线(如表格)时,容易因循环累加浮点误差导致某几根线错位。建议:
- 用
Math.round(x * dpr) / dpr对齐逻辑坐标(更稳妥的取整) - 或者直接在缩放后使用整数坐标绘制,例如:
for (let i = 0; i <br><code> const y = Math.round(i * cellSize + 0.5); // +0.5 对齐像素中心ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(width, y); ctx.stroke();} - 关闭抗锯齿(可选,部分场景有效):
ctx.imageSmoothingEnabled = false;ctx.mozImageSmoothingEnabled = false;
关键不在“怎么设 lineWdith”,而在于“在哪画”和“用多少像素画”。DPR 适配决定上限清晰度,坐标偏移 0.5 决定 1px 线条能否真正锐利。两步缺一不可。


















