使用网页字体时如何避免FOUT(无样式文本闪烁)问题?
解决方案
现有代码的核心问题是执行顺序错误:在Google Font的CSS样式表加载完成前就调用了document.fonts.load(),此时浏览器还没有解析到对应字体的@font-face规则,load()方法会优先匹配本地安装的同名字体直接触发回调,等后续CSS加载完成、实际网络字体开始下载时,回调已经执行完毕触发了样式切换,就会出现FOUT。
修正步骤
- 先给link元素绑定load事件,等Google Font的CSS文件加载、解析完成,
@font-face规则注册到文档后,再触发字体加载逻辑 - 给
document.fonts.load()传入第二个参数作为测试文本,避免字体包含特殊字符集时加载判断异常 - 额外判断
font.status状态,确保字体完全加载后再执行回调
修正后代码
function requestGoogleFont(fontFamily, fontWeight, fontStyle, doOnLoad) { let fontDesc = [fontStyle, fontWeight, '14px', fontFamily + ', ', 'sans-serif'].join(' '), headElement = pageFrameContents.head, fontVariant = fontStyle === 'italic' ? fontWeight + 'italic': fontWeight, url = 'https://fonts.googleapis.com/css?family=' + fontFamily.split(' ').join('+') + ':' + fontVariant, link = html.createAndAppend(headElement, '<link rel="stylesheet">'); fontLoadInitiator.style.font = fontDesc; // 等待CSS加载完成,@font-face规则注册后再加载字体 link.onload = function() { const frameDoc = pageFrame.contentWindow.document; // 传入测试文本,有特殊字符需求可自行调整 frameDoc.fonts.load(fontDesc, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') .then(function() { // 二次校验字体是否确实加载完成 const isLoaded = frameDoc.fonts.check(fontDesc); if (isLoaded) { doOnLoad(); } }); } link.setAttribute("href", url); }
额外优化方案
如果要彻底消除FOUT的感知,可以在字体加载完成前给iframe内容设置临时的visibility: hidden,等回调执行后再恢复可见,比定时器方案更准确,不会出现额外的等待时长。
内容的提问来源于stack exchange,提问作者Stephen Miller
相关产品推荐
相关产品推荐

