问题在于 1) 自定义字体很棒,我们想使用它们 2) 自定义字体作为大型附加资源会减慢页面加载速度。最近一直在讨论如何解决这个问题,因此我想总结一些想法并加上我自己的思考。
仅在大屏幕上加载
我看到的第一个想法是 Dave Rupert 关于仅在大屏幕上加载 @font-face 的测试。事实证明,如果您使用 @font-face 但从未应用该字体系列,则不会下载该字体。浏览器很聪明。Dave 的演示。
@font-face {
font-family: 'Dr Sugiyama';
font-style: normal;
font-weight: 400;
src: local("Dr Sugiyama Regular"), local("DrSugiyama-Regular"), url(http://themes.googleusercontent.com/static/fonts/drsugiyama/v2/rq_8251Ifx6dE1Mq7bUM6brIa-7acMAeDBVuclsi6Gc.woff) format("woff");
}
body {
font-family: sans-serif;
}
@media (min-width: 1000px) {
body {
font-family: 'Dr Sugiyama', sans-serif;
}
}
Jordan Moore 在 Typekit 博客上有一篇文章 “移动设备上的备用字体”,它采用了相同的思路。
我将此思路应用到我自己的项目中,创建了两个单独的字体套件:一个“完整”字体套件,包含我最初打算使用的所有排版样式,以及一个“轻量级”套件,包含较少的字体(因此重量明显更轻)。我根据用户屏幕的宽度通过 JavaScript 加载这些套件,值基于最小的断点。
使用 Dave 的技术,您无需担心 FOUT(未设置样式文本的闪烁),因为它使用的是原生 @font-face,并且大多数浏览器都已解决了这个问题。我认为 Jordan 的技术更容易出现 FOUT,需要在测试后加载字体,但您可以像以往使用 Typekit 解决 FOUT 一样解决它:在字体加载时使用 visibility: hidden
。
字体中的 Ajax
如果您的主要关注点是减慢渲染时间(不一定是非完全加载页面的时间),您可以在文档就绪后通过 Ajax 加载包含 @font-face 内容的样式表。Omar Al Zabir 有一个关于此的教程。(感谢 Kevin)
$(document).ready(function(){
$.ajax({
url: fontFile,
beforeSend: function ( xhr ) {
xhr.overrideMimeType("application/octet-stream");
},
success: function(data) {
$("<link />", {
'rel': 'stylesheet'
'href': 'URL/TO/fonts.css'
}).appendTo('head');
}
});
});
确保字体文件具有较远的过期标头也很重要。为了在此处解决 FOUT 问题,您需要向 <html>
元素添加一个类(立即使用 JavaScript),并使用它来 visibility: hidden
您想要隐藏的内容,直到字体加载,并在 Ajax 成功回调中将其删除。
延迟加载字体,在缓存后加载后续页面加载
扩展此想法,也许我们只有在非常确定字体文件已缓存的情况下才能显示自定义字体。在后端,我们检查一个 cookie(我们稍后将自行设置),该 cookie 指示字体已缓存。
// Check if cookie exists suggesting fonts are cached
if (fonts_are_cached) {
echo "<link rel='stylesheet' href='/URL/TO/fonts.css'>";
}
在前端,我们将执行完全相反的操作。如果不存在该 cookie,我们将延迟加载这些字体,然后设置该 cookie。
// Check if cookie exists suggesting fonts are cached
if (!fonts_are_cached) {
// Don't slow down rendering
$(window).load(function() {
// Load in custom fonts
$.ajax({
url: 'URL/TO/font.woff'
});
$.ajax({
url: 'URL/TO/font.eot'
});
// Don't actually do anything with them, just request them so they are cached.
// Set cookie indicating fonts are cached
});
}
并非万无一失,因为该 cookie 无法 100% 证明字体已缓存。但是,如果您将其设置为在一天后过期,它仍然有相当大的几率。这里没有 FOUT,因为它要么根本不加载字体,要么使用 @font-face 本地加载。如果您不介意 FOUT(即,无论如何您都希望在第一次页面加载时显示自定义字体),您可以创建 <link>
并插入字体样式表,而不仅仅是请求字体。
另一种方法是将字体的 data URI 版本放入 localStorage 中,并在需要时将其提取出来。您将创建一个 <style>
元素,使用字体的 data URI 版本将 @font-face 代码放入其中,并将其注入。显然,卫报正在尝试这样做。
@scottjehl 关于缓存讨论的相关信息:卫报正在使用 localStorage。 github.com/guardian/front… @davatron5000 @chriscoyier
— Tim Kadlec (@tkadlec) 2013年4月17日
公平警告,localStorage 可能比缓存慢。
@tkadlec @scottjehl @davatron5000 @chriscoyier 如果您绝对需要,本地存储有效,但读取速度可能比浏览器缓存慢
— Addy Osmani (@addyosmani) 2013年4月17日
使用 JavaScript 花哨功能的一个可能的优势是知道您需要哪些字体版本。
@davatron5000 @sturobson @chriscoyier 我们正在使用 insertBefore 加载 data uri 的字体。默认为 WOFF.css,如果 Android/IE 则使用 TTF 或 EOT
— Scott Jehl (@scottjehl) 2013年4月17日
未来
我们可以获得更多关于客户端情况的信息,所有这些都会变得更好。
他们获得什么样的带宽和延迟?这很难(而且很繁重)进行测试,即使我们可以测试,可靠性也不高。也许 网络信息 API 将在将来有所帮助。
他们的屏幕尺寸是多少?浏览器的功能是什么?我们可以在 JavaScript 中测试这些内容,但如果在服务器端了解这些内容会更好怎么办?也许 Client-Hints 将在将来有所帮助。
网页字体会被缓存,对吧?所以这只是一个初始加载的问题?
使用您的延迟加载方法……要么我遗漏了什么,要么整个第一页视图都是一个巨大的“FOUT”。也许这就是您所说的“尴尬”的意思 。
不,整个第一页将不会有自定义字体。刷新网站或转到任何子页面时,才会出现漂亮的字体。我说的对吗?
希望我能更快地学习 Javascript :)
查看 codecademy.com,他们有很棒的免费 Javascript 和 jQuery 学习课程
另一个快速提示:如果您正在托管字体文件,它们也可以被 gzip 压缩(除了 WOFF 格式),节省 40-70% 的大小。请参阅 压缩您的 @font-face 文件 和 @font-face 和性能 以获取更多详细信息。
Ajax 方法纯粹是“炫耀”……
定义“炫耀”:炫耀通常具有很大价值的物品(Urban Dictionary)。
我不太了解——但我认为“媒体查询”方法就足够了……即使在南非也是如此 #说真的。
非常有用的文章。
同意 @Archie Makuwa 的观点。我认为“媒体查询”解决方案是最简单和可靠的解决方案。我希望我们可以使用带宽媒体查询! https://css-tricks.org.cn/bandwidth-media-queries/
对我来说,基于宽度的媒体查询方法是错误的。设备尺寸是带宽的非常糟糕的指标,此外,在我的台式机上,我有一个普通的屏幕。
在我的 Nexus 4 上,我有一个漂亮的 HDPI 屏幕,在我的 iPad 上,我有一个视网膜屏幕——那么我想要在哪些设备上获得超级清晰的漂亮字体?——那些可能被媒体查询排除在外的设备。
恕我直言,我们必须(我相信我们会)达到可以可靠地检测用户连接速度的程度——NetworkInformation 和 Connection 接口看起来很有希望,尽管有点遥远。
在我们真正知道用户下载我们发送的数据的速度之前,我们无法优化他们的体验——目前最好的方法是通过使所有场景下的页面尽可能轻量来优化每个人。
对于响应式图像来说,这是一个更大的问题,而不是字体,因为我们无法有效地缓存以获得快速的全站体验。
哦,如果“媒体全部和(最小速度:〜1Mbps){}”等等!!
目前,如果客户的网站对速度非常敏感(希望有可靠的分析数据和用户研究作为支持),我只会使用网络安全字体,虽然无聊但速度快。或者如果我们不使用斜体,就使用经过良好优化的轻量级字体栈(通常来自 Typekit)作为折衷方案,我们不加载斜体!
我同意应该将“大屏幕”测试更改为连接速度测试。任何使用移动设备的人都有可能使用超快的 Wi-Fi – 为什么给他们不同的字体?
我认为 Foresight.JS 将是一个不错的起点。我不确定您是否会认为它“可靠”,但一些信息总比没有好。
是的,FOUT 是我真正想要避免的事情,即使只是最初。使用 Typkit 和 Google 字体之类的东西都很好,但我发现将实际字体存储在站点目录中并在样式表中调用它们效果很好。当然,这会增加一些页面重量,但我认为权衡是值得的,真的有那么糟糕吗?
此外,我注意到,不仅链接到其他服务器上的字体时会出现 FOUT,而且如果回退字体具有不同的行高或填充,某些元素可能会稍微偏移。增加了尴尬…
您错了 – 托管字体文件几乎总是比自己托管更快。大多数托管字体都位于 CDN 上,这始终比非 CDN 托管更快。此外,在您的域名上托管的文件将按顺序加载,通常一次加载 2 个… 而在另一个域名上托管的文件将与您域名上的文件并行加载。最后,托管的字体文件(例如 Google CDN 上的 Open Sans)很可能已缓存在用户的浏览器中… 这意味着当用户首次访问您的网站时,文件根本不会加载。如果您决定自己托管 Open Sans,则它必须为每个访问您网站的用户加载。
我最近发布了一个关于我如何提供字体的视频。它并没有真正涵盖本文中的任何内容,但涉及子集、编码等。你们可能想看看。
优秀的教程,易于理解的信息,尤其是极佳的音频质量。谢谢。
我发现媒体查询也是最佳解决方案。
我们掌握的关于客户情况的信息越多,所有这些都会变得越好!
IE <= 8 会下载未使用的字体。以下是 IE7 和 IE8 的结果。
感谢这篇文章… 我一直在寻找解决这个问题的方法。有时 Google Webfonts 会让我的页面加载速度变得非常慢。期待我们找到一种标准化的方法来解决这个问题。
看,我的问题是:自定义字体究竟会造成多大的性能损失?在我的一个网站上,该网站是移动优先设计的,我使用的两种字体似乎并没有减慢加载速度——可能是因为其他方面非常轻量级——我无法弄清楚如何将字体作为加载时间中的一个因素隔离出来。
如果您使用的是 Chrome,则可以使用检查器。右键单击页面上的某个位置,然后转到“检查元素”,然后单击“网络”选项卡并使用强制刷新重新加载页面(CTRL+SHIFT+R)
应该可以从输出中获得一些了解
这很有用。很长一段时间以来,我一直想知道页面加载时间是否值得牺牲,仅仅是为了使用自定义字体,因为有很多人的互联网连接速度很慢,这对他们来说是一个很大的阻碍。例如,如果我在几秒钟内看不到任何文字——我就会离开页面。
就我个人而言,我无法为了更好的性能而忽略使用自定义字体,但我认为很容易通过选择使用哪些字体以及使用多少字体来节省一些页面重量。我通常使用 Google 字体 API 并选择最多 2 种最流行的字体,因为这样流行字体已经被下载和缓存的可能性要大得多。
感谢您对此进行澄清… 自定义字体在企业环境中绝对可用,例如 Facebook 等公共网站?宁可不… – 完全不考虑交付的性能。
我不知道 AJAX 方法。这对我来说将非常有用。您能否告诉我是否有标准化的方式来执行此操作?
对于 Typekit,我们仅在通过媒体查询检测到屏幕尺寸时加载。几周前,我们为此创建了一个教程 此处(我刚刚将其翻译成英文,如果看到任何错别字,请见谅!)。该方法 来自 Jeremy Keith 和一些条件加载测试。这是另一种方法,随时与我们联系!
这里有很棒的笔记。我还要补充一种技巧,它将我的自定义字体文件大小从 900KB 减少到 17KB。
并非总是最佳选择,但仍然非常有趣。我在 此网站 上使用了 Cufón。Cufón 是一个小型 JavaScript 引擎,允许您加载所需的特定字符。我甚至有机会为 Inspired Mag 撰写一篇关于此的教程。查看一下!
(编辑:删除了失效链接)
似乎使用媒体查询的方法最简单。问题是您无法通过宽度测试了解用户的设备或连接速度。当然,“可能性很大”>1200px 可能是台式机,但实际上可能是任何东西。
我想这取决于网站所有者研究他们的分析并更准确地确定他们拥有哪种用户群体,然后确定使用潜在重量较大的字体是否是一个可以接受的决定。
非常棒的文章。我喜欢自定义字体,但我讨厌减慢我的网站速度。我一定会采用其中一些技巧!
虽然字体是一个问题,但我仍然看到大量网站在文档的头部(字面意思)链接了十几个 CSS 文件,以及可能数量相同的链接 JavaScript 文件。通常,在提供这些文件之前,这些文件都没有进行 gzip 压缩。与单个 100kb 字体文件相比,我更担心 10 个 10kb 的链接文件。
我的感觉是,在他们担心放弃他们喜欢的字体之前,人们可以做很多其他事情来提高文档的加载时间和渲染时间。但这并不意味着我们不应该明智行事——除非您真的、非常需要 3 种不同粗细和斜体的字体,否则请不要包含这些变体!
关于 Google 字体的疑问;
仅对一个标题使用 Google 字体与对网站上的所有文本使用 Google 字体,在加载时间(或性能)方面是否存在任何差异?
由于字体文件的实际下载是主要影响加载时间的原因,我认为对所有内容使用该字体不会有任何区别?但我只是在猜测..
/Simon
有人看到过关于不同字体类型(ttf、woff、svg)的渲染速度(而不是下载速度)的基准测试吗?如果没有,如何衡量它?
非常有趣,很棒的文章。我在 PingDom 上设置了 RUM(真实用户监控),这是一个前端用户监控服务。它比 GA(Google Analytics)提供了好得多的用户体验跟踪,因为它专门用于衡量用户经历的过程。我现在已经有了几百次访问量,并且看到了一些有趣的数据。它测量
重定向 -> DNS -> 连接 -> 发送 -> 接收 -> DOM 处理 -> 渲染
有趣的是,我的页面加载中位数总体为 1.4 秒,对此我非常满意。但是,在我的图表中,我可以看到渲染时间出现了一些巨大的峰值,其中一个长达 35 秒。
据我所知,这是我使用过的唯一能够提供此类数据的工具,因此我想分享一下。您只需设置一些类似于分析的代码,并且代码是异步加载的,文件也很小,因此对网站没有实际影响。
不过,我仅仅是触及了表面,在移动设备和平板电脑的渲染时间方面也有一些非常有趣的数据。它包含浏览器信息、体验指数、按国家/地区数据、按页面数据等等。
还有其他人使用过类似的工具吗?
当我和客户谈话时,我该如何准确地解释webfont会产生多大的影响?我是否正确地认为它只有大约 200kb 到 400kb 的信息,所以大约相当于在他们网站首页的大型英雄滑块上添加另一张照片?如果它是像 Open Sans 这样常见的字体,他们的许多网站访问者是否已经缓存了该字体?如果我错了,请纠正我。
这里或那里 400kb 确实会累积起来。这就是为什么现在平均网页(包括其所有资源)的重量超过 1mb 的原因。是的,如果您从 Google CDN 提供 Open Sans,那么您的访问者很有可能已经缓存了它,但如果您选择不常用字体且不使用/无法使用 CDN,那么与使用访问者本地安装的 Web 安全字体相比,将会有性能损失。
我比较老派,当任何单个资源的大小超过 50kb 时,我都会感到害怕 :-)
我对这件事的看法是
1) 如果您使用外部字体,请尝试使用 CDN 上的字体。
2) 尝试使用“标准”字体,例如 Open Sans、Droid Sans 等。您的访问者更有可能缓存这些字体,并且它们已被证明能够可靠地渲染/显示。
3) 尝试不要使用超过 1 个,最多 2 个自定义字体。我认为使用 3 个或更多不同字体的网站看起来可能很奇怪。
4) 如果您使用图标字体,请通过 Icomoon.io 等工具运行它们,这样您就可以只选择所需的图标,从而大大减小字体的尺寸。
谢谢!我最近访问了一些使用三到四个 Web 字体的网站,以及各种粗细,加上到处都是大型滑块和图形,这些网站太重了。但我认为对于我目前的客户来说,一个通用的 Web 字体就足够了——她希望她的网站更新看起来焕然一新,我认为其中一部分将是选择一种新的字体。
我只是想知道在网站中使用自定义字体的哪种方式更好更快。
是通过 @font-face 方法还是 Google Fonts。
它们都使用 @font-face。因此,延迟取决于您的主机与 Google 相比提供文件的速度。