字体加载失败或回退不生效是HTML5小游戏关键体验问题:需用document.fonts.load()确保字体就绪再绘制、@font-face须覆盖所有字重样式、measureText()须等字体激活后调用,否则引发布局跳动与错位。

字体加载失败或回退不生效,是 HTML5 小游戏里最常被忽略却影响体验的关键问题——不是代码写错了,而是字体资源没加载完就渲染、或 @font-face 声明没覆盖所有字重/样式,导致浏览器用系统默认字体撑开布局,文字突然跳动、错位甚至空白。
字体还没加载完,canvas 就画了文字
Canvas 2D 上调用 fillText() 时,如果指定的 font 名称尚未被浏览器解析完成(哪怕 CSS 已声明 @font-face),它会静默降级到默认无衬线字体,且不会触发重绘。你看到的“异常”,其实是文字宽度突变引起的布局偏移或遮挡。
- 务必在
document.fonts.load()返回的 Promise 解决后,再执行首次fillText() - 不要依赖
window.onload或DOMContentLoaded,它们不保证字体就绪 - 示例:
document.fonts.load('bold 16px "PixelFont"').then(() => { // 此时 canvas 绘制才安全 ctx.font = 'bold 16px "PixelFont"'; ctx.fillText('START', 100, 100); });
@font-face 没配全字重和斜体,导致 fallback 失效
小游戏里常需 bold、italic、bold italic 多种样式,但只声明了常规体?浏览器会尝试合成,而 Canvas 和 CSS 渲染对合成字体的支持差异极大——CSS 可能勉强显示,Canvas 却直接回退到系统字体,造成视觉断层。
- 每个实际用到的
font-weight和font-style组合,都得有独立的@font-face规则 - 确保
src中的字体文件路径可访问,且格式兼容(推荐woff2+woff双备) - 避免用通配符如
font-weight: 400 700;,要拆成两条规则分别定义
Canvas 文字测量不准,因为字体未激活就调了 measureText()
ctx.measureText() 返回的 width 值,完全取决于当前 ctx.font 是否已绑定真实字体。若字体还在加载中,它按默认字体计算,后续真实字体加载后,文字实际宽度变了,UI 元素就错位。
立即学习“前端免费学习笔记(深入)”;
- 所有涉及文字宽度计算的逻辑(如按钮自动缩放、居中定位),必须等
document.fonts.load()完成后再执行 - 不要缓存
measureText()结果到全局变量,除非你确认字体已就绪且不会再切换 - 可加一层防护:
if (document.fonts.check('bold 16px "PixelFont"')) { const w = ctx.measureText('SCORE').width; } else { // 用预估宽度占位,或延迟计算 }
最麻烦的不是加载慢,而是「看起来加载完了」——比如字体文件返回 200 但内容损坏,或 CORS 阻止了字体解析,此时 document.fonts.load() 仍可能 resolve。真要稳,得结合 document.fonts.status 和主动校验文本渲染结果。











