在渲染网页之前等待字体加载
Posted
技术标签:
【中文标题】在渲染网页之前等待字体加载【英文标题】:Wait for fonts to load before rendering web page 【发布时间】:2011-06-10 09:07:22 【问题描述】:我正在使用@font-face 在我的网站中嵌入字体。首先文本呈现为系统默认值,然后(一旦字体文件可能已加载)正确的字体会在几分之一秒后呈现。有没有办法通过将页面渲染延迟到字体加载或类似之后来最小化/消除这种延迟。
【问题讨论】:
缓存字体会起作用。 请记住,这是让您的网站看起来很慢的好方法,因为无线链接上的用户可能需要一段时间才能加载网络字体。如果文本在几秒钟内没有出现,许多用户只会点击返回按钮。 这能回答你的问题吗? How to be notified once a web font has loaded 【参考方案1】:我在渲染到 html 画布时遇到了类似的问题,这是我的解决方案。它基于 FontFace API,类似于 Holtwicks 方法。主要区别在于这是一种通用方法,并且它可以开箱即用地用于外部字体/样式表(例如 google 字体)。
几个笔记;
如果字体未知,fonts.load( ... )
将很乐意用一组空字体解决。据推测,如果在添加声明字体的样式表之前调用此代码,则会发生这种情况。我添加了fonts.check(...)
来解决这个问题。
这将让您等待 javascript 执行,直到字体可用,因此对于“普通”HTML 内容,它不会开箱即用。您可以将其与上面的 Holtwicks 答案结合使用。
export async function waitForFontLoad(
font: string,
timeout = 1000,
interval = 10
)
return new Promise((resolve, reject) =>
// repeatedly poll check
const poller = setInterval(async () =>
try
await document.fonts.load(font);
catch (err)
reject(err);
if (document.fonts.check(font))
clearInterval(poller);
resolve(true);
, interval);
setTimeout(() => clearInterval(poller), timeout);
);
【讨论】:
【参考方案2】:这段代码对我来说效果很好。它使用Font Loading API,在现代浏览器中得到了很好的支持。
<style>
@font-face
font-family: 'DemoFont';
font-style: normal;
font-weight: 400;
src: url("./fonts/DemoFont.eot");
src: url("./fonts/DemoFont.woff2") format("woff2"),
url("./fonts/DemoFont.woff") format("woff"),
url("./fonts/DemoFont.ttf") format("truetype");
.font
font-family: 'DemoFont';
color: transparent;
html.font-loaded .font
color: inherit; // Override `transparent` from .font
</style>
<script>
// Check if API exists
if (document && document.fonts)
// Do not block page loading
setTimeout(function ()
document.fonts.load('16px "DemoFont"').then(() =>
// Make font using elements visible
document.documentElement.classList.add('font-loaded')
)
, 0)
else
// Fallback if API does not exist
document.documentElement.classList.add('font-loaded')
</script>
诀窍是为使用该字体的元素将 CSS 颜色设置为透明。加载后,通过将 font-loaded
类添加到 <html>
元素来重置它。
请将DemoFont
替换为对您的项目有意义的内容以使其正常运行。
【讨论】:
这个问题的一个问题是fonts.load('10px Nothing')
很乐意用一个空的字体列表来解决。您需要结合 load
和 check
。【参考方案3】:
使用https://github.com/typekit/webfontloader
并检查配置中的事件 https://github.com/typekit/webfontloader#configuration
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
<script>
WebFont.load(
custom:
families: [ "CustomFont1", "CustomFont2" ]
,
active: function()
//Render your page
);
</script>
【讨论】:
【参考方案4】:编辑:最好的方法可能是base64 编码你的字体。这意味着您的字体必须在您的 HTML 被解析和显示时完全加载。您可以通过单击“专家”然后单击“base64 编码”来使用字体松鼠的 webfont 生成器https://www.fontsquirrel.com/tools/webfont-generator 来完成此操作。这就是 TypeKit 等服务的工作方式。
原答案: 另一种检测字体是否已加载的方法是使用 FontLoader https://github.com/smnh/FontLoader 或复制它们的策略。
它们绑定到浏览器中的滚动事件,因为当字体加载时它会调整文本大小。它使用两个包含的 div(当高度变化时会滚动)和一个单独的 IE 后备。
另一种方法是使用setInterval
定期检查 DOM,但使用 javascript 事件更快更好。
显然,您可能会执行一些操作,例如将 body 的不透明度设置为 0,然后在字体加载后显示它。
【讨论】:
我真的很喜欢 base64 解决方案!为我工作! 我尝试通过一些 JavaScript 代码将 base64 编码字体插入<style>
标签。之后,我测量文本的大小。但它(至少)不适用于 Safari(ios 15),因为我将大小作为默认字体应用而不是新字体。【参考方案5】:
由于没有人提到这一点,我相信这个问题需要更新。我设法解决问题的方法是使用现代浏览器支持的“预加载”选项。
如果有人不需要支持旧浏览器。
<link rel="preload" href="assets/fonts/xxx.woff" as="font" type="font/woff" crossorigin>
一些包含更多细节的有用链接:
https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content http://www.bramstein.com/writing/preload-hints-for-web-fonts.html
【讨论】:
这是最好的答案,自定义字体在未使用时不会加载。这个会立即加载,因此第一次使用字体时不会出现框字体 在 Chrome 91、Safari 14、Firefox 89 和 Opera 77 上完美运行! 我有一个脚本,它依赖于实际文本的宽度和高度,但它从应用自定义字体之前获取它们。这解决了它! 这将预加载字体并使其在渲染 DOM 时可能可用。但是,由于它不是阻塞的,它仍然不能保证在页面渲染之前加载自定义字体。【参考方案6】:您可以在 @font-face 中使用 CSS font-display。 所有可用值的关键字是:
自动 阻止 交换 后备 可选Giulio Mainardi 写了一篇关于它们的好文章,你应该在 sitepoint 上使用它。
您可以在这里阅读:https://www.sitepoint.com/css-font-display-future-font-rendering-web/?utm_source=frontendfocus&utm_medium=email
【讨论】:
这是 2020 年正确且首选的方法。不要因为用户连接不稳定而惩罚用户,但如果您真的必须使用font-display: block
。绝对不要做 what Ryan Taylor suggested 和 base64-encode 任何事情;没有用户愿意下载 30% 以上的数据,这样您就可以阻止渲染直到下载完成,即使(不,尤其是,在移动连接上时)如果它“只是”一个问题例如300kB。【参考方案7】:
这取决于浏览器的行为方式。
首先你的@font 声明在哪里?它是嵌入到您的 HTML 中,在页面上的 CSS 表中声明,还是(希望)在外部 CSS 表中声明?
如果它不在外部工作表中,请尝试将其移至一张(这通常是更好的做法)。
如果这没有帮助,您需要问问自己,秒差的一小部分是否真的对用户体验有很大的不利影响?如果是,那么请考虑 JavaScript,您可能可以做一些事情,重定向、暂停等,但这些实际上可能比原来的问题更糟糕。对用户来说更糟,维护也更糟。
此链接可能会有所帮助:
http://paulirish.com/2009/fighting-the-font-face-fout/
【讨论】:
您能做的最好的事情是听从 Tom 的建议,另外,确保您的客户端在后续页面加载时不会访问 Web 服务器,因为这是一个真正的字体渲染阻止程序——设置一个过期时间CSS 文件的标头和实际字体资源的标头,一切顺利。 好文章。让我们希望 Firefox 在不远的版本中采用 safari 方法来加载字体。 FOUT 过去对我来说不是问题,但是对于我正在处理的当前站点,自定义字体与任何系统字体都非常不同,所以第一次闪光非常明显。跨度> 大字体(即 200 Kb)和慢速连接(即 3G)不是一秒钟的时间。对于那些使用带有 SIM 芯片的平板电脑的人来说,设计人员应该考虑这种情况。【参考方案8】:(function()
document.getElementsByTagName("html")[0].setAttribute("class","wf-loading")
document.getElementsByTagName("html")[0].setAttribute("className","wf-loading")
)();
使用此方法.. 与 Webfont.js 一起使用
【讨论】:
【参考方案9】:Joni Korpi 有一篇关于在页面其余部分之前加载字体的好文章。
http://jonikorpi.com/a-smoother-page-load/
他还使用 loading.gif 来缓解延迟,这样用户就不会感到沮丧。
【讨论】:
【参考方案10】:只有 IE 会先加载字体,然后再加载页面的其余部分。 其他浏览器出于某种原因同时加载内容。想象一下,托管字体的服务器或字体下载存在问题。 在加载字体之前,您将挂起整个站点。在我看来,一闪而过的无样式文本总比根本看不到网站要好
【讨论】:
好吧,除非您在同一个网站上托管字体。 还有,除非字体是引导字形图标 还有,除非您需要知道字形的像素大小。flash of unstyled text
使您的用户认为您(创建者)在您的工作中不专业,并且应用程序存在一些错误。这是 UX 人。【参考方案11】:
可能是这样的:
$("body").html("<img src='ajax-loader.gif' />");
然后当页面加载时,将正文的内容替换为实际内容,并希望完全呈现字体,但您可能不得不玩这个...
【讨论】:
以上是关于在渲染网页之前等待字体加载的主要内容,如果未能解决你的问题,请参考以下文章