在一次前端性能优化项目中,我们发现仅仅一个 icon font 文件就高达 20MB 。这不仅拖慢了首屏加载速度,还极大地浪费了带宽。最终,我们将它压缩到了 10KB,而不影响任何功能表现。
这一过程背后,涉及的不仅是压缩,而是对「构建流程」「字体格式」「加载策略」「字形定制」的全盘重构。本文将逐步拆解这场"减重手术",帮助你理解 icon font 是如何成为性能黑洞的,又是如何优雅瘦身的。
问题:20MB 的 icon font 是怎么来的?
大字体文件往往是由于以下原因造成的:
- 过度收录:设计同学导出了一整套 2000 多个图标的 icon font,实际只用了其中几十个。
- 全量打包:工具如 Icomoon、Fontello、FontForge 默认导出全量字形。
- 格式冗余 :一个字体文件常包含
.ttf
,.woff
,.woff2
,.eot
,.svg
多种格式,全打包增加体积。 - 不做 Subset(子集提取):没有剔除未使用的字形。
最终结果就是:用户下载了 2000 个图标,只为了看到那 20 个常用 icon。
目标:精简为只包含实际使用 icon 的最小字体
如果你只用了 <i class="icon-chevron-down"></i>
、<i class="icon-close"></i>
、<i class="icon-search"></i>
三个图标,那字体文件里应该只包含这三个图形。
核心理念是:用子集字体(Subset Font)只保留被真正使用的字形。
解决方案路线图
✅ 步骤一:收集实际用到的 icon
- 全站代码扫描,提取 icon class(或 unicode)
- 工具:自定义脚本、AST 分析、静态资源分析工具
bash
# 示例:查找 iconfont 使用的 class 名称
grep -roh 'icon-[a-zA-Z0-9_-]\+' ./src | sort | uniq > used-icons.txt
✅ 步骤二:精简 icon 到最小集合
工具选择:
- IcoMoon App:可视化管理图标,导出精简 icon font
- FontSubset:支持上传字体,自动子集提取
pyftsubset
(来自 fonttools):命令行方式自动提取子集
例:使用 pyftsubset
bash
pyftsubset original.ttf \
--unicodes=U+E001,U+E002,U+E003 \
--output-file=subset.ttf \
--flavor=woff2 \
--layout-features='*' \
--no-hinting \
--glyph-names
说明:
--unicodes
指定只保留的字符--flavor=woff2
输出现代浏览器首选格式--no-hinting
去除微调信息,减小文件体积
✅ 步骤三:只保留必要的字体格式
浏览器现代化后,建议:
- 只保留
.woff2
(现代浏览器支持) - 视兼容性决定是否保留
.woff
(老一点的 Chrome/Firefox) - 移除
.eot
/.svg
/.ttf
除非需要极限兼容 IE6+
字体大小差异:
格式 | 同内容文件大小 |
---|---|
TTF | 40KB |
WOFF | 28KB |
WOFF2 | 10KB |
✅ 步骤四:字体精简之后如何正确加载?
CSS 示例:
css
@font-face {
font-family: 'MyIcons';
src: url('icons.woff2') format('woff2');
font-display: swap;
}
重点字段说明:
font-display: swap
:加速首次渲染format('woff2')
:浏览器可判断是否支持
✅ 步骤五:如果你用的是组件库的内建 iconfont
Ant Design、Element UI、Bootstrap Icons 等往往内置大量 iconfont。优化策略如下:
-
替换为 SVG 图标组件 (例如 Iconify)
-
只引入需要的图标模块
- Antd 4.x 以上支持按需引入图标(非字体形式)
-
使用 Tree-shaking 友好的 SVG icon 方案
- 如
@iconify/react
、@icon-park/react
- 如
成果验证
经过上述处理:
- 初始字体大小:20.3MB
- 实际保留字形数量:12 个
- 精简后字体(.woff2)大小:10.4KB
- 首屏加载 TTI 提升:约 800ms
- Lighthouse 性能评分:+9 分
额外干货:你可能不知道的字体优化技巧
🧠 1. 使用 base64 inline 的 icon font 并非总是好事
虽然可减少 HTTP 请求,但:
- 无法缓存(每次 HTML 载入)
- 增加 HTML 大小
- 不利于 CDN 优化和延迟加载
通常只有在 icon font < 5KB 且需要打包进组件时,才考虑 base64。
🧠 2. 字体子集可以配合 SSR 实现动态优化
在 SSR 应用(如 Next.js)中,可以:
- 在构建阶段根据页面中实际 icon 自动生成对应的字体子集
- 动态注入只需要的 icon font,达到更极致的优化效果
🧠 3. 替代方案:彻底摆脱 icon font,用 SVG
SVG 优点:
- 完全控制颜色/动画
- 无需额外字体解析
- 体积更小,支持按需加载
- 更适合现代组件式开发(React/Vue)
推荐库:
- Iconify(80+ 图标集统一封装)
- unplugin-icons(Vite 项目自动加载)
- Heroicons、Feather、Lucide、Tabler 等
你还在用几兆的 icon font,不妨静下心来,用一下午把它瘦成精悍的 10KB, 别让一堆你永远不会用到的图标,霸占用户的加载时间。