SVG 还是 Font Icon?现代前端项目的图标最佳实践
对比 SVG Icon 和 Font Icon 的优缺点,为什么现代前端开发越来越倾向于使用 SVG?如何管理和优化 SVG 资源?
几年前,FontAwesome 还是我的项目标配。只要引入一个 CSS 文件,就能用类名随便调图标,感觉方便极了。但是随着项目变大,我发现 Font Icon 的问题越来越多:图标模糊、对齐困难、为了几个图标加载几百 KB 的字体文件... 后来我彻底转向了 SVG 方案,虽然初期配置麻烦点,但带来的灵活性和性能提升绝对物超所值。
不过 SVG 也有让人头疼的地方,尤其是直接用设计师给的文件。Sketch 或 Illustrator 导出的 SVG 里面往往塞满了乱七八糟的元数据、注释和冗余的 Group 标签。有时候一个简单的圆圈图标,代码能有几十行!每次拿到新图标,我都得先去 SVG 压缩工具里过一遍,不然看着代码洁癖都要犯了。
1. 字体图标 (Icon Font) 的没落
曾经,字体图标因为兼容性好(支持 IE6!)、体积小(相比雪碧图)而风靡一时。但随着 Web 技术的发展,它的劣势逐渐显现:
- 渲染问题:浏览器把图标当文字处理,容易出现锯齿,且受抗锯齿设置影响,不同系统下粗细不一。
- 对齐困难:图标作为文字,受行高、基线等排版属性影响,很难与旁边的文本完美垂直居中。
- 加载闪烁:FOIT (Flash of Invisible Text) 问题,字体文件加载慢时图标会显示为空白方框。
- 维护成本:增加一个图标通常需要重新生成字体文件,多人协作时容易冲突。
2. SVG 的全面胜利
SVG (Scalable Vector Graphics) 本质上是 XML 代码,它天生适合 Web。
完美的清晰度
无论放大多少倍,边缘永远清晰锐利,完美支持 Retina 屏幕。
CSS 可控性
可以通过 CSS 控制填充色 (fill)、描边 (stroke),甚至给路径添加动画效果。
语义化与可访问性
SVG 内部可以包含 <title> 和 <desc> 标签,对屏幕阅读器非常友好。
按需引入
结合 Tree Shaking,只打包使用到的图标,零冗余。
3. Vue/React 项目中的最佳实践
在现代框架中,最推荐的方式是将 SVG 封装为组件。以 Vue 为例,可以使用 `unplugin-icons` 这样的插件,或者手动封装一个通用 Icon 组件:
<Icon name="lucide:home" class="w-6 h-6 text-primary" />
这种方式利用了 Iconify 的海量图标库,结合纯 CSS 的遮罩或 SVG Sprite 技术,既保持了开发体验,又保证了性能。OneKit 网站本身就大量使用了这种方案(基于 Nuxt Icon 模块)。
4. SVG 优化小贴士
- 移除冗余代码:使用 SVGO 工具移除 XML 声明、注释、未使用的 ID 等。
- 使用 currentColor:将 SVG 的 fill 或 stroke 属性设置为 `currentColor`,这样它就会自动继承父元素的 color 属性,方便通过 CSS 改色。
- viewBox 很重要:确保所有图标使用相同的 viewBox(如 0 0 24 24),这样控制大小时比例才一致。