资讯专栏INFORMATION COLUMN

一种不完美的网页字体异步加载方法

xiaokai / 2369人阅读

摘要:在字体的过程中,先用一种最接近目标字体的安全字体来显示,等字体文件加载完后进行替换。第个方案是一种迫不得已的选择,在用户眼皮底下更换字体,是非常影响体验的,好处是字体属于异步加载,不会阻塞文本显示。

问题

最近在做一个项目时,遇到了这样一个问题:网页大标题要用设计师指定的中文字体,该字体文件比较大,浏览器加载字体文件的过程中是不会显示使用该字体的文本的,于是出现了初次打开网页时有一段时间“No title”的BUG。

解决方案

针对该问题,笔者能想到以下几种解决方案(欢迎补充):

把文字做成png图片,或改为路径后做成SVG图片,考虑做成base64内嵌到CSS文件。

使用字体工具,将字体包中没用到的字符删除来减小字体文件的体积(npm上也有这样的优秀JS库)。

方案1的升级版,在所有用到这个字体的文本中,把首屏出现的文本做成图片,后面的文本依然使用字体包,并在打开首页时就加载字体包。

方案2的升级版,在向服务器请求字体的时候,由服务端分析document中所有用到的字符,动态生成字体包后返回给浏览器端。

在loading字体的过程中,先用一种最接近目标字体的安全字体来显示,等字体文件加载完后进行替换。

打死设计师,想用啥用啥。

方案对比与选择

由于后续的页面内容也有不少文本会用到该字体,且考虑今后网站维护成本,所以1、2两个解决方案不适合本项目。

第3个方案最省事,做快速开发的话比较合适,但代码复用性不高,程序也不够健壮,例如低网速情况下,有可能会出现字体包未完全加载时用户已经滑到下一页,而这一页中有文本是使用了目标字体包从而不显示的情况。

第4个方案需要后端开发的配合,要考虑如何判断所有用到的字符,并且在JS向document中写入新的字符时,要请求增量字体包,会较大程度地增加CDN服务端负担(主要是怕跟后端开发撕逼)。

第5个方案是一种迫不得已的选择,在用户眼皮底下更换字体,是非常影响体验的,好处是字体属于异步加载,不会阻塞文本显示。

最后一个方案成本比较高,需要搭上开发人员的下半辈子,好处是可以从根本上解决这个BUG,永诀后患。被逼急的程序员可以尝试下。

结合项目特点,最终选择方案5。

实现过程

整个过程逻辑非常简单:首先标题所用的class在CSS中被定义了一个最接近目标字体的安全字体,然后等待字体文件加载,加载完成后将标题的class换成自定义字体的class。

首先设好两个CSS属性,一个是用最接近目标字体的安全字体,用于默认字体,第二个是自定义字体:

/* 定义字体 */
@font-face{
    font-family: Lanting_light;
    src: url("../res/font/goDieDesigner.woff");
}
/* 安全字体,用于默认 */
.lanting_l{
    font-family: Arial, Helvetica, sans-serif;
}
/* 自定义字体 */
.lanting_light{
    font-family: "Lanting_light",Arial, Helvetica, sans-serif;
}

元素设置成默认字体:

我是一段可爱的文字,啾咪~

写一个函数,用于替换元素的class,在字体文件加载完成后执行它:

function onLoadedFont() {
    ele = document.getElementsByClassName("Lanting_l");
    for (let i = 0; i < ele.length; i++){
        ele[i].classList.add("Lanting_light");
        ele[i].classList.remove("Lanting_l");
    }
}

接下来是整个问题的核心:如何判断字体文件已被加载?

一个html元素,可以用监听load事件来判断加载,但字体不是html元素,无法监听。
再来看一下需求,字体文件是从用户打开页面时就要开始加载了,所以只要让字体一开始就加载,然后监听window.load事件就好了:

window.addEventListener("load",onLoadedFont);

PS:这里不太严谨,可能会有其他大体积资源加载拖慢load事件,所以大文件最好用lazyload。MDN提供了一个属性可以判断字体加载,但是目前兼容性还有一些问题,这里就先不用了,感兴趣的可以看一下这里。小弟才疏学浅,如有大神知道其他监听字体文件加载的方法,还请留言告知,谢谢~

然后就是要做些什么让字体文件一开始就去加载了,要知道不同浏览器什么时候会去加载一个字体,可以参考这篇文章。
在HTML中创建一个文本标签,让它去用这个需要被加载的字体,并且让这个文本不要出现在视窗中:

字体

最后擦个屁股,load完成后把上述已经被榨干剩余价值的节点删掉:

window.addEventListener("load",function(){
    let dev = document.getElementsByClassName("Lanting_light");
    for (let i = 0; i < dev.length; i++){
        dev[i].parentElement.removeChild(dev[i]);
    }
    //必须先删除旧节点后再修改需要改的节点,否则文本节点会被删掉
    onLoadedFont();
});

到这里,整个功能就完成了。

总结

总结一下,这个方案可以让字体文件没有加载完的时候,先用一个接近的安全字体让文本先显示出来,待字体加载完后再换字体,核心的点是监听字体文件的加载,因为MDN上提供的document.font是一个实验性功能,兼容性不是很好,所以这里用了投机取巧的办法去监听window.load,可能会被其他大文件阻塞,也会拖慢监听window.load的其他函数,所以在项目中还是要取舍,没有完美的方案,只有最合适的方案。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106210.html

相关文章

  • 博客引入漂亮字体二三事

    摘要:火狐推迟对字体的支持,重点放在格式上。网络字体的效率字体文件的体积可能非常的大尤其是对于汉字,而且需要额外的连接,这些都会降低网站页面的加载速度。 最近兴致上来,就想更换了那Blog标题字体(汉字的);网上搜索了一番,发现蘇新詩柳繁體这款甚合我心;然后就着手搞将了起来,分分钟也算是替换了;但,这仅仅是此次折腾的开始;这就细细道来作为学习笔记记载。 原文首发链接http://www.je...

    Pocher 评论0 收藏0
  • 博客引入漂亮字体二三事

    摘要:火狐推迟对字体的支持,重点放在格式上。网络字体的效率字体文件的体积可能非常的大尤其是对于汉字,而且需要额外的连接,这些都会降低网站页面的加载速度。 最近兴致上来,就想更换了那Blog标题字体(汉字的);网上搜索了一番,发现蘇新詩柳繁體这款甚合我心;然后就着手搞将了起来,分分钟也算是替换了;但,这仅仅是此次折腾的开始;这就细细道来作为学习笔记记载。 原文首发链接http://www.je...

    Michael_Lin 评论0 收藏0
  • [译] 如何运用新技术提升网页速度和性能

    摘要:简言之,我们认为好的用户体验从快速的内容传输开始,也就意味着性能美观。每一步我们都在探讨如何在获得好的用户体验和保证设计美感的同时,最小化对性能的影响。字型子集设定到目前为止,子集设定是改善网页字体性能最快的方式。 作者 Declan 原文链接 最近更新了我们的网站,它是经过了设计上的全面验收的。但实际上,作为软件开发者,我们会注重很多技术相关的零碎的东西。我们的目标是控制性能,注重性...

    zhoutk 评论0 收藏0
  • [译] 如何运用新技术提升网页速度和性能

    摘要:简言之,我们认为好的用户体验从快速的内容传输开始,也就意味着性能美观。每一步我们都在探讨如何在获得好的用户体验和保证设计美感的同时,最小化对性能的影响。字型子集设定到目前为止,子集设定是改善网页字体性能最快的方式。 作者 Declan 原文链接 最近更新了我们的网站,它是经过了设计上的全面验收的。但实际上,作为软件开发者,我们会注重很多技术相关的零碎的东西。我们的目标是控制性能,注重性...

    he_xd 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<