根本原因是ios canvas严格按字体度量计算基线,而filltext默认以baseline为y锚点,导致文字上浮或偏移;需显式设置完整font、慎用middle/alphabetic基线,优先用top/bottom并配合translate定位,且保存前必须等待ctx.draw(true, callback)完成。

canvas文字在iOS真机偏移的根本原因
这不是渲染bug,是坐标系理解偏差。iOS端Canvas的fillText默认以文字基线(baseline)为y锚点,而基线位置受字体、字号、系统字体渲染引擎影响极大。H5和Android上可能“碰巧对齐”,但iOS(尤其微信小程序基础库2.21.3+)会严格按字体度量计算,导致同一段代码在iOS上文字整体上浮或右漂。
常见错误现象包括:setTextAlign('center')后文字仍明显左偏、textBaseline = 'middle'实际却贴着顶部、多行文字逐行偏移加剧。
必须显式设置textBaseline和font
不设font就调fillText,iOS会回退到不可控的系统默认字体(如San Francisco),其度量值与你预期的'14px sans-serif'完全不同。
-
ctx.font必须写全,例如'bold 16px Helvetica Neue, sans-serif',避免依赖继承或默认值 -
ctx.textBaseline优先用'top'或'bottom',它们语义明确、跨端稳定;慎用'middle'或'alphabetic',iOS上容易失准 - 如果必须居中显示,不要只靠
textBaseline = 'middle',而是手动算出视觉中心:先用ctx.measureText(text)获取宽度,再结合ctx.font估算行高,最后推导y坐标
绕开基线陷阱:用translate + fillText组合定位
当文字需精确定位(比如水印、标注),直接传入绝对x/y风险高。更可靠的做法是:
- 用
ctx.translate(x, y)把原点移到目标位置 - 设
ctx.textBaseline = 'top'且ctx.setTextAlign('left') - 调
ctx.fillText(text, 0, 0)——此时文字左上角就落在(x, y) - 用
ctx.setTransform(1, 0, 0, 1, 0, 0)重置坐标系,避免污染后续绘制
这个模式彻底规避了baseline语义歧义,iOS/Android/H5表现一致。
保存前必须等ctx.draw(true, callback)完成
iOS canvasToTempFilePath空白图90%源于此:没等绘制真正结束就调保存。尤其在文字叠加场景下,字体加载、光栅化都是异步过程。
- 每次调
ctx.fillText后,必须跟ctx.draw(true, () => { /* 保存逻辑 */ }) -
true参数强制清空画布队列,callback确保GPU渲染帧已提交 - 切勿在
draw回调外直接调uni.canvasToTempFilePath,否则iOS返回透明图
iOS Canvas文字偏移最隐蔽的坑不在绘制逻辑本身,而在「你以为画完了,其实还没」——那个true参数和回调,不是可选项,是iOS平台的硬性门槛。











