前言
Hexo Butterfly 主题默认使用 FontAwesome 图标库,虽然功能强大,但在某些场景下存在一些不足:
- 🚫 图标种类受限:FontAwesome 的图标虽然丰富,但无法满足所有个性化需求
- 🐌 加载速度较慢:完整的 FontAwesome 库体积较大
- 🎨 自定义困难:无法使用自己设计的图标
而阿里云的 iconfont 矢量图标库则完美解决了这些问题:
- ✅ 海量图标资源,支持上传自定义 SVG
- ✅ 按需加载,只引入需要的图标
- ✅ 完全免费,国内访问速度快
本文将详细介绍如何在 Butterfly 主题中集成 iconfont,并通过配置文件统一管理所有图标。
一、什么是 Iconfont?
Iconfont(图标字体) 是一种将图标以字体形式引入网页的技术。阿里云的 iconfont 平台提供了:
- 海量图标库:数百万个图标可供选择
- 项目管理:可以创建项目,将需要的图标添加到项目中
- 多种引入方式:支持 Unicode、Font class、Symbol 等多种方式
- 自定义上传:支持上传自己设计的 SVG 图标
为什么选择 Symbol 引用方式?
Iconfont 支持三种引用方式:
| 方式 | 优点 | 缺点 |
|---|
| Unicode | 兼容性好 | 不支持多色图标,语义不明确 |
| Font class | 语义明确,使用方便 | 不支持多色图标 |
| Symbol | 支持多色图标,矢量无失真 | 需要浏览器支持 SVG |
本文采用 Symbol 引用方式,优势如下:
- ✅ 支持多色图标
- ✅ 通过 SVG 渲染,图标质量高
- ✅ 可以通过 CSS 控制颜色和大小
- ✅ 语义化程度高
二、在阿里云 Iconfont 创建项目
1. 注册并登录
访问 iconfont.cn,使用支付宝或 GitHub 账号登录。
2. 创建图标项目
- 点击右上角”资源管理” → “我的项目”
- 点击”新建项目”
- 填写项目信息:
- 项目名称:如
hexo-blog-icons - 前缀:
icon-(重要!后续会用到) - FontClass/Symbol 前缀:
icon-
3. 添加图标到项目
有两种方式添加图标:
方式一:搜索并添加现有图标
- 在首页搜索框输入关键词,如”搜索”、”菜单”等
- 找到喜欢的图标,点击”加入购物车”
- 点击右上角购物车图标,选择”添加至项目”
- 选择你创建的项目
方式二:上传自定义 SVG
- 在项目页面点击”上传图标”
- 选择 SVG 文件(需要是单色或多色的矢量图)
- 系统会自动生成图标
4. 生成在线链接
- 进入你的项目页面
- 点击”Symbol” 标签
- 点击”生成代码” → “复制代码”
- 得到类似这样的链接:
1
| //at.alicdn.com/t/c/font_4961003_rqnmjsg0krh.js
|
三、在 Butterfly 主题中引入 Iconfont
1. 在配置文件中引入 JS
编辑 _config.butterfly.yml,找到 inject 配置项:
1 2 3 4 5 6
| inject: head: - <script src="//at.alicdn.com/t/c/font_4961003_rqnmjsg0krh.js"></script> - '<style>.icon {width: 1.5em; height: 1.5em; vertical-align: text-bottom; fill: currentColor; overflow: hidden;}</style>'
|
注意事项:
- ⚠️ 每次在 iconfont 项目中添加新图标后,需要重新生成代码并更新这个链接
- ⚠️ 建议使用
// 开头的协议相对路径,自动适配 http/https
2. 配置图标管理系统
在 _config.butterfly.yml 的最前面添加全局图标配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
icons: nav: search: icon-sousuo menu_toggle: fas fa-bars post: edit: icon-bianji calendar: icon-rili updated: icon-gengxin category: icon-fenlei separator: icon-jiantou wordcount: icon-wenzi readtime: icon-shijian views: icon-yulan comments: icon-pinglun sticky: icon-zhiding pagination: prev: fas fa-chevron-left next: fas fa-chevron-right index: calendar: icon-rili updated: icon-gengxin category: icon-fenlei category_separator: icon-jiantou tag: icon-biaoqian comment: icon-pinglun sticky: icon-zhiding aside: webinfo: icon-tongji announcement: icon-gonggao tags: icon-biaoqian recent_post: icon-wenzhang newest_comment: icon-pinglun toc: icon-mulu post_series: icon-xilie webinfo_item: article_count: icon-wenzhang runtime: icon-yunxing total_wordcount: icon-wenzi site_uv: icon-yonghu site_pv: icon-fangwen last_push: icon-gengxin copyright: author: icon-zuozhe link: icon-lianjie notice: icon-banquan
|
四、修改模板文件支持 Iconfont
核心思路
要让主题支持 iconfont,需要修改相应的 Pug 模板文件。核心思路是:
- 创建 renderIcon mixin:根据图标名称判断是 iconfont 还是 FontAwesome
- 从配置读取图标:从
_config.butterfly.yml 读取图标配置 - 条件渲染:根据前缀
icon- 判断使用哪种渲染方式
renderIcon Mixin 实现
1 2 3 4 5 6 7 8 9 10 11
| //- 图标渲染混入(Mixin) mixin renderIcon(iconClass, extraClass) if iconClass - const isIconfont = iconClass.startsWith('icon-') if isIconfont //- 渲染 iconfont(SVG) svg.icon(class=extraClass aria-hidden="true") use(xlink:href='#' + iconClass) else //- 渲染 FontAwesome i(class=iconClass + (extraClass ? ' ' + extraClass : ''))
|
实战案例 1:导航栏搜索图标
文件位置:themes/butterfly/layout/includes/header/nav.pug
修改前(硬编码):
1 2 3 4
| #search-button span.site-page.social-icon.search i.fas.fa-search.fa-fw span= ' ' + _p('search.title')
|
修改后(可配置):
1 2 3 4 5 6 7 8 9 10
| #search-button span.site-page.social-icon.search - const searchIcon = theme.icons && theme.icons.nav && theme.icons.nav.search || 'fas fa-search' - const isIconfont = searchIcon.startsWith('icon-') if isIconfont svg.icon.fa-fw(aria-hidden="true") use(xlink:href='#' + searchIcon) else i.fa-fw(class=searchIcon) span= ' ' + _p('search.title')
|
实战案例 2:文章页面图标
文件位置:themes/butterfly/layout/includes/header/post-info.pug
修改要点:
- 在文件开头定义
renderIcon mixin - 从配置中读取图标:
theme.icons.post.calendar - 使用 mixin 渲染图标
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| //- 定义 mixin mixin renderIcon(iconClass, extraClass) if iconClass - const isIconfont = iconClass.startsWith('icon-') if isIconfont svg.icon(class=extraClass aria-hidden="true") use(xlink:href='#' + iconClass) else i(class=iconClass + (extraClass ? ' ' + extraClass : ''))
//- 使用 mixin .post-meta-date - const calendarIcon = theme.icons && theme.icons.post && theme.icons.post.calendar || 'far fa-calendar-alt' +renderIcon(calendarIcon, 'post-meta-icon') span.post-meta-label= _p('post.date') time.post-meta-date-created= date(page.date, config.date_format)
|
实战案例 3:侧边栏卡片图标
文件位置:themes/butterfly/layout/includes/widget/card_tags.pug
完整示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| //- 图标渲染 mixin mixin renderIcon(iconClass, extraClass) if iconClass - const isIconfont = iconClass.startsWith('icon-') if isIconfont svg.icon(class=extraClass aria-hidden="true") use(xlink:href='#' + iconClass) else i(class=iconClass + (extraClass ? ' ' + extraClass : ''))
if theme.aside.card_tags.enable .card-widget.card-tags .item-headline //- 从配置读取图标 - const tagsIcon = theme.icons && theme.icons.aside && theme.icons.aside.tags || 'fas fa-tags' +renderIcon(tagsIcon, '') span= _p('aside.card_tags') .card-tag-cloud!=tagcloud({min_font: theme.aside.card_tags.limit ? 15 : 13, max_font: theme.aside.card_tags.limit ? 20 : 20, amount: theme.aside.card_tags.limit, color: theme.aside.card_tags.color, orderby: theme.aside.card_tags.orderby, order: theme.aside.card_tags.order})
|
实战案例 4:社交媒体图标
文件位置:themes/butterfly/layout/includes/header/social.pug
支持颜色自定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| //- 带样式的 mixin mixin renderIcon(iconClass, extraClass, iconStyle) if iconClass - const isIconfont = iconClass.startsWith('icon-') if isIconfont svg.icon(class=extraClass aria-hidden="true" style=iconStyle) use(xlink:href='#' + iconClass) else i(class=iconClass + (extraClass ? ' ' + extraClass : '') style=iconStyle)
each url, icon in theme.social - const [link, title, color] = url.split('||').map(i => trim(i)) const href = url_for(link) const iconStyle = color ? `color: ${color.replace(/[\'\"]/g, '')};` : '' const iconTitle = title || '' a.social-icon(href=href target="_blank" title=iconTitle) +renderIcon(icon, '', iconStyle)
|
配置示例:
1 2 3 4
| social: icon-bilibili: https://space.bilibili.com/xxx || B站 icon-github: https://github.com/xxx || GitHub icon-email: mailto:xxx@example.com || Email || '#4a7dbe'
|
五、需要修改的文件清单
根据图标位置,需要修改以下 Pug 模板文件:
1. 导航相关
- ✅
themes/butterfly/layout/includes/header/nav.pug - 搜索、菜单按钮
2. 文章相关
- ✅
themes/butterfly/layout/includes/header/post-info.pug - 文章元信息图标 - ✅
themes/butterfly/layout/includes/post/post-copyright.pug - 版权信息图标
3. 首页相关
- ✅
themes/butterfly/layout/includes/mixins/indexPostUI.pug - 首页文章列表图标
4. 侧边栏相关
- ✅
themes/butterfly/layout/includes/widget/card_announcement.pug - 公告卡片 - ✅
themes/butterfly/layout/includes/widget/card_tags.pug - 标签卡片 - ✅
themes/butterfly/layout/includes/widget/card_webinfo.pug - 网站信息卡片 - ✅
themes/butterfly/layout/includes/widget/card_recent_post.pug - 最近文章卡片 - ✅
themes/butterfly/layout/includes/widget/card_newest_comment.pug - 最新评论卡片 - ✅
themes/butterfly/layout/includes/widget/card_post_toc.pug - 目录卡片 - ✅
themes/butterfly/layout/includes/widget/card_post_series.pug - 文章系列卡片 - ✅
themes/butterfly/layout/includes/widget/card_author.pug - 作者信息卡片
5. 其他组件
- ✅
themes/butterfly/layout/includes/pagination.pug - 分页按钮 - ✅
themes/butterfly/layout/includes/header/social.pug - 社交媒体图标
六、实际效果展示
配置前后对比
使用 FontAwesome(默认):
1 2 3
| icons: nav: search: fas fa-search
|
渲染结果:
1
| <i class="fas fa-search fa-fw"></i>
|
使用 Iconfont:
1 2 3
| icons: nav: search: icon-sousuo
|
渲染结果:
1 2 3
| <svg class="icon fa-fw" aria-hidden="true"> <use xlink:href="#icon-sousuo"></use> </svg>
|
混合使用示例
可以在同一个配置中混合使用 FontAwesome 和 iconfont:
1 2 3 4 5 6
| icons: post: calendar: icon-rili category: fas fa-folder tag: icon-biaoqian comment: far fa-comments
|
七、常见问题与解决方案
Q1:图标不显示怎么办?
可能原因 1:iconfont JS 未加载
检查方法:
- 按
F12 打开浏览器开发者工具 - 切换到 Network 标签
- 刷新页面,搜索
font_ 关键词 - 确认 JS 文件加载成功(状态码 200)
可能原因 2:图标名称错误
检查方法:
1 2 3
| Array.from(document.querySelectorAll('symbol[id^="icon-"]')) .map(s => s.id)
|
这会列出所有可用的图标名称,确认你使用的名称是否存在。可能原因 3:浏览器缓存
解决方法:
- 按
Ctrl + F5 强制刷新 - 或在开发者工具中勾选 “Disable cache”
Q2:如何快速查找图标?
在 iconfont 网站:
- 使用中文或英文关键词搜索
- 可以按”下载量”、”收藏量”排序
- 点击图标可以预览不同尺寸效果
推荐搜索关键词:
- 搜索:
search, sousuo, 放大镜 - 菜单:
menu, caidan, 汉堡 - 标签:
tag, biaoqian, 标记 - 时间:
time, clock, rili, 日历
Q3:更新图标后不生效?
每次在 iconfont 项目中添加或修改图标后:
- 在 iconfont 网站点击”更新代码”
- 复制新的 JS 链接(注意版本号会变化)
- 更新
_config.butterfly.yml 中的链接 - 清理 Hexo 缓存:
Q4:如何自定义图标样式?
在 themes/butterfly/source/css/custom.css 中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| .icon { width: 1.2em; height: 1.2em; }
.post-meta-icon.icon { width: 1em; height: 1em; margin-right: 0.3em; }
.social-icon .icon { transition: all 0.3s; }
.social-icon:hover .icon { transform: scale(1.2); color: #49b1f5; }
|
八、优化建议
1. 按需添加图标
不要一次性添加太多图标到项目中,只添加实际使用的图标,可以:
- ✅ 减小 JS 文件体积
- ✅ 加快页面加载速度
- ✅ 方便管理和维护
2. 使用语义化的图标名称
在 iconfont 项目中给图标设置有意义的名称:
❌ 不推荐:icon-001, icon-abc
✅ 推荐:icon-search, icon-menu, icon-calendar
3. 定期更新和备份
- 定期检查图标是否还在项目中
- 导出项目配置进行备份
- 记录每次更新的图标清单
4. 建立图标命名规范
建议使用统一的命名规范:
1 2 3 4 5 6 7 8 9
| icon-search-article icon-view-count icon-tag-cloud
icon-sousuo icon-biaoqian icon-fenlei
|
九、总结
通过本文的配置,我们实现了:
✅ 统一管理:所有图标在一个配置文件中集中管理
✅ 灵活替换:随时可以更换任何图标,无需修改代码
✅ 性能优化:按需加载,只引入使用的图标
✅ 个性化:可以使用自定义 SVG 图标
✅ 兼容性:支持 FontAwesome 和 iconfont 混用
配置流程回顾
1 2 3 4 5 6 7 8
| graph LR A[注册 iconfont] --> B[创建项目] B --> C[添加图标] C --> D[生成代码] D --> E[引入到 Hexo] E --> F[配置图标] F --> G[修改模板] G --> H[测试效果]
|
核心代码
配置文件(_config.butterfly.yml):
1 2 3 4 5 6 7
| inject: head: - <script src="//at.alicdn.com/t/c/font_xxx.js"></script>
icons: nav: search: icon-sousuo
|
模板文件(所有 .pug 文件):
1 2 3 4 5 6 7 8
| mixin renderIcon(iconClass, extraClass) if iconClass - const isIconfont = iconClass.startsWith('icon-') if isIconfont svg.icon(class=extraClass aria-hidden="true") use(xlink:href='#' + iconClass) else i(class=iconClass + (extraClass ? ' ' + extraClass : ''))
|
希望这篇文章能帮助你成功配置 iconfont,让你的博客更加个性化!如果有任何问题,欢迎在评论区讨论。
参考资源