预加载@font-face 字体?

Posted

技术标签:

【中文标题】预加载@font-face 字体?【英文标题】:Preloading @font-face fonts? 【发布时间】:2010-11-22 18:46:55 【问题描述】:

是否可以在页面加载之前预加载或以其他方式缓存 @font-face 字体(最有可能使用 javascript),以便在页面最终加载时不会出现丑陋的跳转?

【问题讨论】:

不能指定height/line-height来避免跳转效果吗? 开始的好地方css-tricks.com/fout-foit-foft developer.mozilla.org/en-US/docs/Web/html/Preloading_content ***.com/a/42683378/7314900 【参考方案1】:

自 2017 年起您拥有preload

MDN:元素的 rel 属性的预加载值允许您 在您的 HTML 中编写声明性获取请求,指定 您的页面在加载后很快就会需要的资源,您 因此希望在页面生命周期的早期开始预加载 在浏览器的主要渲染机制启动之前加载。这 确保它们更早提供并且不太可能 阻止页面的第一次渲染,从而提高性能。

<link rel="preload" href="/fonts/myfont.eot" as="font" crossorigin="anonymous" />

始终检查browser compatibility。

它对于字体预加载最有用(不等待浏览器在某些 CSS 中找到它)。您还可以预加载一些徽标、图标和脚本。

其他技术的优缺点在here(不是我的博客)中讨论。 另请参阅 prefetch(类似)和关于 preload vs prefetch 的 SO 问题。

【讨论】:

crossorigin is required even if the font is loaded from the same origin。也可以提供类型提示。 @IlpoOksanen 现已添加 但是如何将字体系列名称分配给加载的字体? @DonDilanga 我认为这是你必须通过 CSS 完成的事情 在 Chrome 91、Safari 14、Firefox 89 和 Opera 77 上完美运行!【参考方案2】:

一个简单的技巧是把它放在你的索引中:

<div class="font_preload" style="opacity: 0">
    <span style="font-family: 'myfontface#1font-family', Arial, sans-serif;"></span>
    <span style="font-family: 'myfontface#2font-family', Arial, sans-serif;"></span>
    ...
</div>

在 Chrome 34、Safari 7 和 FF 29 以及 IE 11 上测试

【讨论】:

这在我的情况下非常有效,可以让字体预加载用于fabricjs。谢谢。 这在我的用例中创造了奇迹(在使用 Web 技术进行打印时可能会很奇怪):我正在尝试使用 CSS 字体并在框中设置文本,但如果框溢出,我可以稍微调整字体大小或字母间距,直到合适为止。但这可以自动化:选择最小和最大字母间距字母间距,并在它们之间进行二进制搜索,以找到适合文本的合适值。但这需要requestAnimationFramesetTimeouts 预渲染字体!这可以解决问题。令人惊讶的是&lt;span&gt;s 可以留空。 但出于可访问性原因,我强烈建议使用role="none presentation"user-select: none; pointer-events: none;,以免干扰用户事件。甚至可能是position: absolute; top: 0; transform: translateY(-100%);【参考方案3】:

这里有一些“预加载”技术: http://paulirish.com/2009/fighting-the-font-face-fout/

主要是诱使浏览器尽快下载文件..

您还可以将其作为 data-uri 提供,这很有帮助。 您还可以隐藏页面内容并在准备好时显示它。

【讨论】:

抱歉,我想挖掘这个,但我怀疑我没有理解某些内容。博客文章上的提示似乎是关于在字体加载时隐藏文本,但如果我只想获取例如Chrome 会尽快加载它,而不是在遇到一些具有该字体的文本时加载它?我最好的选择是 中的隐藏 div 吗?【参考方案4】:

你的头应该包括如下的预加载:

<head>
    ...
    <link rel="preload" as="font" href="/somefolder/font-one.woff2">
    <link rel="preload" as="font" href="/somefolder/font-two.woff2">
</head>

这种方式 woff2 将被支持预加载的浏览器预加载,并且所有后备格式都将像往常一样加载。 你的 css 字体应该和这个类似

@font-face 
    font-family: FontOne;
    src: url(../somefolder/font-one.eot);
    src: url(../somefolder/font-one.eot?#iefix) format('embedded-opentype'),
    url(../somefolder/font-one.woff2) format('woff2'), //Will be preloaded
    url(../somefolder/font-one.woff) format('woff'),
    url(../somefolder/font-one.ttf)  format('truetype'),
    url(../somefolder/font-one.svg#svgFontName) format('svg'); 

@font-face 
    font-family: FontTwo;
    src: url(../somefolder/font-two.eot);
    src: url(../somefolder/font-two.eot?#iefix) format('embedded-opentype'),
    url(../somefolder/font-two.woff2) format('woff2'), //Will be preloaded
    url(../somefolder/font-two.woff) format('woff'),
    url(../somefolder/font-two.ttf)  format('truetype'),
    url(../somefolder/font-two.svg#svgFontName) format('svg');

【讨论】:

最好在中加入如下属性type="font/woff2"crossorigin,防止浏览器出错。否则,这是我的情况的最佳答案。【参考方案5】:

避免 FOIT:不可见文本的闪烁

当然,第一步是在 HTML 中预加载字体:

<link rel="preload" href="pacifico.woff2" as="font" crossorigin="anonymous">

请注意,字体总是预加载启用cross-origin resource sharing (CORS),even though the font resides on the same server:

当预加载启用 CORS 获取的资源(例如 fetch()、XMLHttpRequest 或字体)时,需要特别注意设置元素的 crossorigin 属性。该属性需要设置为匹配资源的 CORS 和凭据模式,即使提取不是跨域的。

因此,crossorigin="anonymous" 属性是绝对必要的。

对于可选的type="MIME-type" 属性不能这样说。对于MIME-type 字体应该是什么,between browsers 和机构存在很多不一致。如果为某个浏览器声明了错误的类型,字体文件将不会被预加载。因此,最好不要同时使用type="MIME-type" HTML 属性。

然后,这就是酷孩子所说的 FOIT; flash of invisible text。 在现代浏览器中,此 FOIT can easily be avoided 通过将 font-display: swap; 属性添加到 @font-face CSS 声明。

@font-face 
  font-family: 'Pacifico';
  font-style: normal;
  font-weight: 400;
  src: local('Pacifico Regular'), local('Pacifico-Regular'), url(pacifico.woff2) format('woff2');
  font-display: swap;

【讨论】:

无需进一步查看。这里有明确的答案。 你写了 href="pacifico.woff2" 但是如果我想将数据存储在 data:application/x-font-woff 而不是外部文件中怎么办?【参考方案6】:

这个答案不再是最新的

请参考这个更新的答案:https://***.com/a/46830425/4031815


不推荐使用的答案

我不知道当前有任何技术可以避免字体加载时闪烁,但是您可以通过为您的字体发送适当的缓存标头并确保该请求尽快通过来将其最小化。

【讨论】:

【参考方案7】:

正确的字体预加载是 HTML5 规范中的一个大漏洞。 我已经经历了所有这些事情,我发现最可靠的解决方案是使用 Font.js:

http://pomax.nihongoresources.com/pages/Font.js/

您可以使用它来使用与加载图像相同的 API 来加载字体

var anyFont = new Font();
anyFont.src = "fonts/fileName.otf";
anyFont.onload = function () 
  console.log("font loaded");

比Google's hulking Webfont Loader更简单、更轻量

这是 Font.js 的 github 存储库:

https://github.com/Pomax/Font.js

【讨论】:

【参考方案8】:

通过 Google 的webfontloader

var fontDownloadCount = 0;
WebFont.load(
    custom: 
        families: ['fontfamily1', 'fontfamily2']
    ,
    fontinactive: function() 
        fontDownloadCount++;
        if (fontDownloadCount == 2) 
            // all fonts have been loaded and now you can do what you want
        
    
);

【讨论】:

你上面的那个人在你两年前给出了完全相同的答案..你为什么还要麻烦再写一次?我很好奇 我的回答只是给出了一个代码 sn-p,人们可以使用它来使用 webfontloader 加载多种字体。上一个答案很好的介绍了webfontloader,但不包含任何代码sn-p。 您应该编辑它而不是重复,并添加代码示例。在问题中重复几乎相同的答案非常令人困惑和浪费滚动。【参考方案9】:

我发现最好的方法是预加载包含字体的样式表,然后让浏览器自动加载它。我在其他位置(在 html 页面中)使用了 font-face,但随后我可以简单地观察字体更改效果。

<link href="fonts.css?family=Open+Sans" rel="preload stylesheet" as="style">

然后在font.css文件中指定如下。

@font-face 
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 400;
  src: local('Open Sans Regular'), local('OpenSans-Regular'),
       url('open-sans-v16-latin-regular.woff2') format('woff2'); /*  Super Modern Browsers */

当通过链接标签预加载字体时,您不能为字体分配名称(如果我错了,请纠正我,我还没有找到方法),因此您必须使用 font-face 将名称分配给字体。尽管可以通过链接标签加载字体,但不建议这样做,因为您不能使用它为字体指定名称。如果没有 font-face 的名称,您将无法在网页的任何地方使用它。根据 gtmetrix,样式表在开头加载,然后按顺序加载其余脚本/样式,然后加载 dom 之前的字体,因此您看不到字体更改效果。

【讨论】:

我使用了这个解决方案,但 Chrome 的 Lighthouse 仍然说这些字体应该被预加载,就好像它没有识别它们一样。我打算换成Andrei的解决方案,看看有什么不同。【参考方案10】:

This 应该可以解决您的问题。

回答您最初的问题:可以。目前只有 Gecko 和 WebKit 浏览器支持它。 你只需要在你的头脑中添加链接标签:

<link rel="prefetch" href="pathto/font">
<link rel="prerender" href="pathto/page">

【讨论】:

您应该小心在页面上预呈现内容。它与预取不同。 为什么是 prerender 而不是 preload ?它是一种字体,而不是 HTML 文件,没有什么可以渲染的 在@font-face的CSS中怎么做? @vsync 很抱歉,如果不清楚,但这是两种不同的方法。一个是特定的(仅预取字体),另一个是通用的(即它将提前获取该页面的资源,包括字体)。 rel="prerender" 具有 PRO(一次获取多种字体)和 CON(获取 所有 资源。使用 caveats)。【参考方案11】:

我通过在我的主文档中添加一些字母并使其透明并分配我想要加载的字体来做到这一点。

例如

<p>normal text from within page here and then followed by:
<span style="font-family:'Arial Rounded Bold'; color:transparent;">t</span>
</p>

【讨论】:

【参考方案12】:

使用标准的CSS Font Loading API。

等待(所有)字体加载,然后显示您的内容:

document.fonts.ready.then((fontFaceSet) => 
    console.log(fontFaceSet.size, 'FontFaces loaded.');
    document.getElementById('waitScreen').style.display = 'none';
);

Demo CodePen.

【讨论】:

现在得到了非常广泛的支持:Font Loading API。比font-display更重要:font-display【参考方案13】:

最近我正在开发一个与 CocoonJS 兼容的游戏,其 DOM 仅限于 canvas 元素 - 这是我的方法:

将 fillText 与尚未加载的字体一起使用将正确执行但没有视觉反馈 - 因此画布平面将保持不变 - 您所要做的就是定期检查画布是否有任何更改(例如循环通过 getImageData搜索任何非透明像素),当字体正确加载时会发生。

我在最近的文章http://rezoner.net/preloading-font-face-using-canvas,686中对这种技术进行了更多解释

【讨论】:

【参考方案14】:

谷歌为此提供了一个不错的库:https://developers.google.com/webfonts/docs/webfont_loader 您几乎可以使用任何字体,并且 lib 会将类添加到 html 标记中。

它甚至会在加载和激活某些字体时为您提供 javascript 事件!

别忘了提供压缩后的字体文件!它肯定会加快速度!

【讨论】:

以上是关于预加载@font-face 字体?的主要内容,如果未能解决你的问题,请参考以下文章

如何预加载 webpack4+babel 捆绑的 CSS @font-face 字体?

无法使用 @font-face 加载字体

如何知道字体(@font-face)是不是已经加载?

使用 Webpack 和 font-face 加载字体

@font-face 字体未加载到 mpdf 中

@ font-face EOT未通过HTTPS加载