必须先strokeText再fillText,因为fillText会覆盖描边内侧约一半线宽,导致描边变细、不均匀或断开;尤其小字号配粗描边时更明显,且抗锯齿下问题更隐蔽。

Canvas文字描边与填充的渲染顺序,直接影响最终视觉效果和性能表现。关键不是“先快还是后快”,而是“先描边再填充”才能保证描边完整可见——因为填充会覆盖描边的一半线宽,尤其在小字号或粗描边时容易出现边缘缺失或模糊。
为什么必须先strokeText再fillText
Canvas在描边时,线条以路径中心为基准向两侧延伸;而fillText是完全覆盖路径内部区域。若先fillText,再strokeText,描边仍能显示,但若反过来先fillText后strokeText,填充内容会遮挡描边靠近内侧的约一半宽度,导致描边变细、不均匀,甚至局部断开。
- 描边线宽为4px时,实际占据路径左右各2px;填充区域紧贴路径内缘,自然覆盖掉左侧那2px的描边
- 字体越小、lineWidth越大,这种覆盖越明显(例如12px字体配3px描边,文字边缘常出现虚化或缺口)
- 抗锯齿开启时,问题更隐蔽但依然存在——像素混合会让描边看起来“发虚”
影响描边清晰度的三个实操细节
顺序只是基础,真正决定描边是否锐利,还取决于这三个设置:
- font属性需明确指定:用ctx.font = "bold 24px sans-serif"而非依赖默认值,避免不同浏览器解析差异导致路径偏移
- textBaseline建议设为"alphabetic":这是fillText/strokeText的默认基线,保持y坐标含义一致;若用"middle"或"top",需同步调整y值,否则描边与填充错位
- 避免过大的lineWidth:16px以上描边在小字号文字上易失真;如需厚重效果,可改用多层strokeText模拟(如偏移±0.5px重复描边)
渐变描边+纯色填充的组合写法
当描边和填充使用不同渐变时,顺序依然不可颠倒,且需分别创建渐变对象:
- 先调用ctx.createLinearGradient()生成描边渐变,赋给ctx.strokeStyle
- 再调用ctx.createRadialGradient()生成填充渐变,赋给ctx.fillStyle
- 严格按strokeText → fillText执行,两个渐变互不影响
- 注意:渐变定义需在对应绘制调用前完成,否则可能取到空或旧渐变
性能提示:批量文字尽量复用样式
频繁切换fillStyle、strokeStyle、font会触发Canvas状态重置,带来轻微开销。对大量同风格文字:
- 统一设置一次ctx.font、ctx.fillStyle、ctx.strokeStyle、ctx.lineWidth
- 用循环连续调用strokeText和fillText,避免中间穿插其他绘图操作
- 如需混排不同样式,优先分组绘制,减少上下文切换次数



















