【问题标题】:How to avoid FOUT when using web fonts?使用网络字体时如何避免 FOUT?
【发布时间】:2021-11-18 15:16:41
【问题描述】:

当我通过用户 UI 加载不同的 Google 字体时,我尝试了不同的方法来避免 FOUT(无样式文本闪烁)。

最初,我认为我可以在链接元素上侦听加载事件,用于从 Google API 请求字体。然而,这个链接并不下载字体本身——它只是下载链接到实际字体文件的@font-face。

此外,当您的浏览器下载了@font-face 时,它​​显然不会下载它链接到的实际字体,直到该字体被页面上的可见文本元素实际使用。 “可见”表示该元素不能通过 display: none 隐藏。

因此,经过进一步挖掘,我决定使用CSS Font Loading API,因为它的设计正是为了处理这些事情。然而,令我失望的是,我仍然得到一个短的 FOUT。我加载谷歌字体的代码:

function requestGoogleFont(fontFamily, fontWeight, fontStyle, doOnLoad) {
    let font = [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">'); // Adds a link element to the head element

    fontLoadInitiator.style.font = font;

    pageFrame.contentWindow.document.fonts.load(font)
        .then(function(returned) {
            doOnLoad();
        });
    link.setAttribute("href", url);
}

您可能已经从代码中猜到了,字体被添加到 iframe 中的文档中。回调 doOnLoad 只是调整 CSS 以应用所选字体。 fontLoadInitiator 指的是页面上的段落元素,其样式为不可见,透明度为:0。它包含一些文本,其作用是让浏览器在下载@font-face 后立即下载字体。

我很失望,即使在使用 CSS 字体加载 API 之后我仍然得到一个短的 FOUT。我可以通过使用一个小的超时来隐藏闪光灯,但实际上我不应该这样做,因为回调应该只在字体完全下载后运行。我没主意了。我希望你们中的一些人过去曾与这只野兽战斗过,并有一些有用的经验可以分享。否则,我唯一的选择是超时(颤抖!)。顺便说一句,我使用的是 Google Chrome 版本 93。

【问题讨论】:

  • 更快的无样式文本> 更慢的样式文本,不要与野兽搏斗,让文本尽快展现并拥抱FOUT
  • @Kareem,谢谢。但这并不是真正的页面加载问题,而是 UI 问题。文本已经可见并且可以通过 UI 进行操作。这很奇怪,因为当一个元素的字体发生变化时,它会在应用新字体之前瞬间变为无样式。

标签: javascript css google-webfonts


【解决方案1】:

经过更多试验,我找到了一个解决方案 - 以及有关 CSS 字体加载 API 的一些见解。尽管 API 已经存在好几年了,但它仍然处于试验阶段,很明显 MDM 上的文档仍然有点缺乏。同样,我主要在 Chrome 中进行了实验。

我发现使用 Promise 不能按预期工作。我已经尝试过 load() 函数以及 ready 属性。根据文档,FontFaceSet.load() 强制下载字体。我认为这意味着在加载完成之前不会解决承诺(受到有关该主题的几篇博文的启发)。但它实际上是非常字面的:它强制下载字体,这意味着我不必设置 fontLoadInitiator 的样式来触发下载。但是,似乎承诺在字体完全下载之前解决 - 因此是 FOUT。

FontFaceSet.ready 属性应该 according to the documentation 包含一个承诺,一旦字体加载和布局操作完成,该承诺就会解决。但是,根据我的经验,事实并非如此。相反,它的行为与 load() 函数返回的承诺完全相同,只是它不将字体作为参数:它在字体完全下载之前解析并导致 FOUT,而且它似乎还强制下载字体(必须属于所有待定字体 - 因为没有传递特定字体),因为它可以在不设置 fontLoadInitiator 样式的情况下工作。

对我有用的是 FontFaceSet.onloadingdone 事件监听器。这确实取决于 fontLoadInitiator 的预样式。如果 fontLoadInitiator 未预先设置样式,则永远不会触发 loadingdone 事件。使用它会删除 FOUT。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 2018-07-13
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    相关资源
    最近更新 更多