字体文件瘦身(前端字体优化)

本文介绍了优化网页中特殊字体的方法,包括转换字体格式(推荐使用WOFF2),按需提取字体(针对小范围使用场景),以及统一渲染时机(利用WebFontLoader)。作者提供了具体工具和步骤来提升加载性能并减少文件大小。

日常开发网页经常会使用一些特殊字体,比如思源黑体、苹方字体等,因为这些字体在一般的宿主环境中是不存在的,需要通过 css 的 @font-face 定义,并从服务器中加载对应的字体文件,而字体文件一般都是比较大的,甚至有时候一个字体比其他所有的资源(js、css、图片)加起来还要大,对网页的加载性能起到非常关键的影响,因此有必要对字体进行一些优化。本文主要从字体格式、按需提取、统一渲染三个方面来谈谈优化字体的常用技巧。

转换字体格式

现在是 1202 年了,各主流设备基本都支持 woff2 字体格式,因此网站中没有必要再引入多种不同格式的字体了。一般地,建议只引入 woff2 就好了,既可以保持代码的简洁性,又可以减少上传到你服务器的文件,何乐而不为?

可是很多时候美术同学只提供其他格式的字体文件给我们,比如 TTF 或 OTF,那如何将其转换成 woff2 呢?

  • TTF 字体转 WOFF2

TTF 字体,是苹果和 windows 都支持的一种字体,因此是美术同学最喜欢用的。TTF 转换 WOFF2 是比较简单的,可以选择线上转换,推荐的网站有以下两个

  • ttf-to-woff2[1]

  • webfont-generator[2]

但是个人觉得线上转换等待上传的时间比较久,而且有时候生成的文件是空白的,因此更加倾向于使用 node 库 ttf2woff2[3] 转换。该库的周下载量达到 10w+ 的,可见好多人都会有将 tff 转换成 woff2 的需求。使用方法也很简单:

cat font.ttf | ttf2woff2 > font.woff2
复制代码

因为使用 了 cat 命令来提取 ttf 的内容,如果你使用的是 windows ,需要使用 git bash 或 wsl 来运行。

  • OTF 转 WOFF2

除了 TTF ,美术同学还经常提供 OTF 给我们,这是微软和 Adobe 共同研发的字体,因此在 windows 平台还是比较流行的。那如何将其转换成 WOFF2 呢?目前我还没有发现哪个线上网站或 node 库能一步到位转换的,在 google 上搜索好几个线上转换的网站,要么转换完成后无法下载 ,要么转换下载后是个空文件,反正就是不靠谱的东西。

经过一番折腾后,找到了一个不错的 python 库 otf2ttf[4],能够稳定的将 otf 转 ttf。使用方法也比较简单,首先安装 python,然后通过 pip 安装 otf2ttf 就可以使用了(pip 类似于 npm,是 python 的包管理器),不过官方的文档中示例代码应该是有一点小笔误:

otf2ttf MyFont.ttf
复制代码

里面的 MyFont.ttf 应该是 MyFont.otf 才对,因为这个 input 应该是 OTF 类型而不是 TTF 。

使用 python otf2ttf 生成 ttf 文件 后,就可以使用上面提到的将 ttf 转换成 woff2 的方法获取到 woff2 了。

关于字体转换的这里再啰嗦一下:有时候美术同学还会提供 ttc 文件给我们,这不是单个字体,而是将多种字体打包在一起了,需要从中提取出 ttf 后才能使用,可以尝试使用 TTC2TTF[5]

按需压缩字体

一般的,尽管将字体转换成 woff2 格式,最小依然也有好几百 K ,而更多情况下会有 1-4M 左右。有时候,我们只有少数的文字需要用到特殊字体,比如说只有 0-9 这 10 个数字用到某种特殊字体,如果把整个字体文件引入就没有必要了,比切10个图片还要大。好在有一些技术能够将 0-9 这10个数字对应的字体子集提取出来。我平时会使用 font-spider 字蜘[6] 来提取。

首先,全局安装 font-spider:

npm install font-spider -g
复制代码

然后,新建一个 html 文件,比如文件名为 index.html ,里面用一个元素包含所有的你想要提取的文字,比如 0-9,并为这个元素定义上你想要的特殊字体:

<h1>0123456789</h1>

<style> @font-face {
  font-family: 'sourceHan';
  src: url('./SourceHanSansCN-Regular.ttf');
  font-weight: normal;
  font-style: normal;
}

h1 {
    font-family: 'sourceHan';
} </style>
复制代码

最后,在这个 html 文件所在的目录执行以下命令:

font-spider index.html
复制代码

这时候,原来的 SourceHanSansCN-Regular.ttf 就会被移动到 .font-spider/ 目录下,而原来位置的字体会被替换成只提取了 0-9 的字体文件。这个体积相差了好几个数量级的:

完整的字体文件大小是 10M :

6734d0c144cc31d607bdb7efde303bcd.png
image.png

只提取 0-9 10 个数字的字体文件只有 7K:

598ece36553bf5f0067824bd2bd3186d.png
image.png

所以,如果你的网站内容是静态不变的,则建议使用 font-spider 将你所要用到的文字提取出来,这将会大大的减少字体文件的体积。

统一渲染时机

将字体转换成 WOFF2 及静态内容网站使用 font-spider 进行按需压缩,可以很好的控制字体的大小。(PS:WOFF2 字体没有必要再开启 GZIP,因为这个字体文本本身就是压缩过的)。

最后,我们再来看看网络速度对字体内容的影响,假如你的网页全部内容都使用某种字体,CSS 定义如下:

@font-face {
  font-family: myfont;
  src: url('./myfont.woff2') format('woff2');
}


body {
  font-family: myfont;
}
复制代码

假如这个 myfont.woff2 文件大小为 4M,而网络下载速度只有 1M/s ,则加载这个字体需要 4 秒钟。这4秒期间由于还没有加载完成远程字体,浏览器会使用什么字体渲染呢?事实上,不同的浏览器表现会不一样的,以下是一些常见的桌面浏览器的表现:

  • IE:它会直接使用备用字体渲染,最后等webfont字体加载完毕后重新渲染。

  • Safari:它会一直等待webfont字体加载完毕,并且期间不会渲染字体。

  • Chrome / Firefox:它们会等待webfont字体加载,如果在3秒之内没有加载完毕,则使用备用字体渲染。最后webfont加载完毕,使用并重新渲染。

我们需要想办法统一这些行为,比较理想的行为是:先使用系统默认字体,等到远程字体加载完成了再替换成特殊字体。借助于 WebFontLoader[7] 可以很容易的实现这一效果。下面来看一下如何使用:

  1. 在 css 中通过 @font-face 定义一个字体:

@font-face {
  font-family: 'myfont';
  src: url('./myfont.woff2') format('woff2');
}
复制代码

注意,CSS 中只需要定义字体就行,而不要使用使用这个字休。

  1. 然后 引入 webfontloader (也可以通过 npm 安装),将你在 css 中定义的字体名称添加到 custom.families 列表中,并在 active 回调中将该字体添加到对应的元素上,代码如下:

<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>
<script> WebFont.load({
  custom: {
    families: ['myfont'],
  },
  classes: false,
  active() {
    document.body.style.fontFamily = 'myfont';
  },
}); </script>
复制代码

这样浏览器一开始就会使用默认字体渲染内容,等字体加载完成后再使用特殊字体重新渲染。

小结

关于字体优化技巧就先写到这里啦,有问题的欢迎留言交流哈。

参考资料

[1]

https://everythingfonts.com/ttf-to-woff2: https://link.juejin.cn/?target=https%3A%2F%2Feverythingfonts.com%2Fttf-to-woff2

[2]

https://www.fontsquirrel.com/tools/webfont-generator: https://link.juejin.cn/?target=https%3A%2F%2Fwww.fontsquirrel.com%2Ftools%2Fwebfont-generator

[3]

https://www.npmjs.com/package/ttf2woff2: https://link.juejin.cn/?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fttf2woff2

[4]

https://github.com/awesometoolbox/otf2ttf: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fawesometoolbox%2Fotf2ttf

[5]

https://www.npmjs.com/package/ttc2ttf: https://link.juejin.cn/?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fttc2ttf

[6]

https://github.com/aui/font-spider: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Faui%2Ffont-spider

[7]

https://github.com/typekit/webfontloader: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Ftypekit%2Fwebfontloader

前端开发中,浏览器性能优化是提升用户体验的关键环节。优化方法可以从多个维度入手,包括网络加载、渲染执行、资源管理、代码结构优化等。以下是一些核心的优化策略和最佳实践。 ### 3. 网络加载优化 - **减少请求数量**:通过合并 CSS、JavaScript 文件,使用雪碧图(CSS Sprites)减少图片请求次数。 - **启用浏览器缓存**:设置合适的 `Cache-Control` 和 `Expires` 头信息,减少重复加载资源。 - **使用 CDN 加速**:将静态资源部署在离用户更近的 CDN 节点上,缩短网络延迟。 - **启用 Gzip 或 Brotli 压缩**:压缩文本资源,减少传输体积。 - **异步加载非关键资源**:使用 `async` 或 `defer` 属性加载非关键 JavaScript,避免阻塞页面渲染[^2]。 ### 3. 渲染与执行优化 - **减少 DOM 操作**:频繁的 DOM 操作会引发重排和重绘,应尽量批量操作或使用虚拟 DOM。 - **避免强制同步布局**:读写 DOM 属性时避免触发强制同步布局,导致性能下降。 - **使用防抖(debounce)与节流(throttle)**:控制高频事件的触发频率,如滚动、调整窗口大小等。 - **利用 Web Workers**:将复杂计算任务移出主线程,避免阻塞 UI 渲染。 - **合理使用懒加载(Lazy Load)**:对图片、视频等资源延迟加载,直到用户滚动到可视区域再加载。 ### 3. 用户体验优化 - **预加载关键资源**:使用 `<link rel="preload">` 提前加载关键字体、脚本或图片。 - **骨架屏(Skeleton Screen)**:在内容加载前展示占位符,提升用户感知速度。 - **服务端渲染(SSR)或静态生成(SSG)**:提升首屏加载速度和 SEO 表现,适用于 Vue、React 等现代框架。 - **优化关键渲染路径(Critical Rendering Path)**:减少关键路径上的阻塞资源,缩短首次渲染时间[^1]。 ### 3. Vue 项目中的性能优化实践 - **组件懒加载(路由懒加载)**:使用 `() => import('...')` 实现按需加载组件。 - **v-if 与 v-show 的合理使用**:频繁切换使用 `v-show`,不频繁切换使用 `v-if`。 - **避免在模板中使用复杂表达式**:将复杂逻辑移至 `computed` 或 `methods` 中。 - **使用 keep-alive 缓存组件状态**:避免重复渲染和状态丢失。 - **使用 Vue Devtools 进行性能分析**:识别组件渲染瓶颈,优化响应速度[^3]。 ### 3. Chrome DevTools 的性能调试技巧 - **Performance 面板**:记录页面加载过程,分析主线程任务、重排重绘、长任务等性能瓶颈。 - **Lighthouse 插件**:生成性能评分报告,提供优化建议,如减少未压缩资源、移除未使用 CSS 等。 - **Network 面板**:监控资源加载时间、大小、请求顺序,识别慢速请求。 - **Memory 面板**:检测内存泄漏,分析对象保留树。 - **Coverage 面板**:查看 CSS/JS 文件中未被使用的代码比例,指导代码瘦身。 ### 3. 示例:使用防抖优化高频事件 ```javascript function debounce(func, delay) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => { func.apply(this, args); }, delay); }; } // 使用示例 window.addEventListener('resize', debounce(() => { console.log('Window resized'); }, 300)); ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值