HTML Canvas绘制的文本仅在页面重新加载时才显示是什么原因
问题根因
这个问题90%的场景是自定义Web字体未完成加载就启动了渲染流程,剩余10%是Canvas font属性不兼容视口单位导致的首次解析失败:
- 如果你用的
this.font_name是通过@font-face引入的外部字体、或者第三方字体库提供的字体,首次打开页面时浏览器需要先下载字体资源,下载完成前Canvas 2D上下文不会按目标字体渲染文本,部分内核甚至会直接跳过文本绘制步骤。等你手动刷新页面时,字体已经被缓存到本地,不需要重新下载,所以文本能正常显示。 - Canvas 2D的
font属性对vh/vw这类视口相对单位的支持并不稳定,部分浏览器在首次布局计算完成前,无法正确把vh单位换算成实际像素值,会把字体大小解析为0或者非法值,直接导致文本不显示。页面重载后布局参数完成缓存,单位解析正常,文本就会出现。 - 极少数情况是
this.text初始值为空,异步赋值后没有触发正确的渲染状态更新,但你提到draw方法每帧都会被调用,这个场景概率很低。
修复方案
按优先级调整代码即可:
- 等字体全部加载完成后再启动渲染循环
直接用原生的字体加载API做监听,不要页面一加载就跑渲染:document.fonts.ready.then(() => { // 此处启动你的requestAnimationFrame渲染循环 runRenderLoop() }) - 提前把视口单位换算成像素值再赋值给font属性,不要直接写vh
// 7vh等价于视口高度的7%,提前算成px单位 const fontSize = window.innerHeight * 0.07 this.ctx.font = `${fontSize}px ${this.font_name}` - 绘制文本前增加字体就绪校验,避免极端场景下渲染失败
参考调整后的draw方法逻辑:public draw() : void { const x : number = this.ctx.canvas.width * this.x_percentage; const y : number = this.ctx.canvas.height * this.y_percentage; const width : number = this.ctx.canvas.width * this.width_percentage; const height : number = this.ctx.canvas.height * this.height_percentage; const text_margin : number = 10; const fontSize = window.innerHeight * 0.07; this.ctx.font = `${fontSize}px ${this.font_name}`; this.ctx.textAlign="center"; this.ctx.textBaseline = "middle"; this.ctx.fillStyle = this.fill_color; this.ctx.fillRect(x, y, width, height); this.ctx.fillStyle = this.text_color; // 校验当前字体是否可用,可用再绘制文本 if (document.fonts.check(this.ctx.font)) { this.ctx.fillText(this.text, x + width / 2, y + height / 2, width - text_margin); } }
内容的提问来源于stack exchange,提问作者136
相关产品推荐
相关产品推荐

