根本原因是未对齐设备物理像素,必须同步设置canvas.width/height属性为逻辑尺寸×dpr、css宽高保持逻辑尺寸、ctx.scale(dpr,dpr)缩放绘图坐标,三者缺一不可。

为什么iOS上Canvas海报文字发虚、边缘毛边
根本原因是没对齐设备物理像素。iOS的Retina屏(如iPhone 12+)pixelRatio普遍为3,但多数人只设了CSS宽高,canvas.width和canvas.height仍用逻辑尺寸(比如375×667),导致系统强行拉伸渲染——插值一糊,锯齿就来了。
必须同时改三处:canvas属性、CSS样式、绘图缩放
缺一不可,漏掉任意一个都会模糊:
-
canvas.width和canvas.height属性必须设为设计宽度 × dpr、设计高度 × dpr(注意:这是DOM属性,不是CSS) -
style.width和style.height保持设计稿逻辑尺寸(如"375px"),控制显示大小 - 调用
ctx.scale(dpr, dpr),且必须在所有绘图操作前执行;每次清空重绘都要重设
onReady里用createSelectorQuery拿canvas节点才可靠
直接在data里写死width/height会失败,因为节点还没挂载。正确时机是onReady钩子中用查询API获取真实节点:
onReady() {
const query = uni.createSelectorQuery()
query.select('#myCanvas').fields({ node: true, size: true }).exec(res => {
const canvas = res[0].node
const dpr = uni.getSystemInfoSync().pixelRatio
const width = res[0].width
const height = res[0].height
canvas.width = width * dpr
canvas.height = height * dpr
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
// 此后所有坐标/字号/线宽都按逻辑尺寸写,不用再乘dpr
})
}
drawImage加载远程图时别传URL,先下载再绘
iOS WebView对跨域图片有降采样行为,直接ctx.drawImage('https://xxx.png')大概率糊且可能空白:
- 用
uni.downloadFile下载到本地临时路径 - 再用
uni.getImageInfo获取真实宽高(含orientation修正) - 最后用
ctx.drawImage绘制——确保原始像素完整载入,不被浏览器二次压缩
真正容易被忽略的是:canvas的width/height属性和ctx.scale()必须成对出现,且缩放后所有绘图参数(包括字体大小、lineWidth)都按逻辑值写——这不是“适配技巧”,而是Canvas在iOS上的渲染铁律。











