网站性能优化实战:PageSpeed Insights 从 47 分到 97 分的优化历程
前言
最近为了优化站点体验, 我决定借助PageSpeed Insights的分析,专项优化站点性能表现.
本文起初基于Cactus主题进行优化, 从47分提高到了94分, 在撰写期间, 又将主题切换到了Icarus, 结果之前的部分优化失效.
不得不重新优化, 但是按照同样思路, 甚至把PageSpeed Insights的分数刷新到了97分.
初始状态分析

PageSpeed Insights 报告显示了以下主要问题:
| 指标 | 初始值 | 问题 |
|---|---|---|
| First Contentful Paint (FCP) | 7.1s | 过慢 |
| Largest Contentful Paint (LCP) | 15.0s | 严重过慢 |
| Cumulative Layout Shift (CLS) | 0.339 | 布局偏移严重 |
| Speed Index | 5.2s | 加载体验差 |
主要的性能瓶颈包括:
- 字体文件过大:MesloLG 字体 TTF 格式高达 636KB
- Font Awesome CSS:加载了完整的图标库 (~19KB) 但只用了几个图标
- 缺少资源预连接:没有对 CDN 等关键资源进行 preconnect
- 图片未优化:Logo 图片 447x432 实际只显示 88x88
- 布局偏移:图片缺少 width/height 属性导致 CLS 问题
第一轮优化:资源瘦身
1. 字体格式转换 (TTF → WOFF2)
WOFF2 是目前最高效的 Web 字体格式,压缩率远超 TTF。
1 | # 使用 ttf2woff2 转换字体 |
效果:636KB → 160KB,减少 75%
然后更新 CSS 中的字体引用,优先使用 WOFF2:
1 | @font-face |
2. 添加 Preconnect 提示
在 <head> 中添加资源预连接,让浏览器提前建立 TCP 连接:
1 | <link rel="preconnect" href="https://cdnjs.cloudflare.com" crossorigin> |
3. Logo 图片优化
原始 Logo 是 447x432 像素,实际显示只需要 88x88。
sips(Scriptable Image Processing System)是 macOS 自带的命令行图片处理工具,无需安装任何第三方软件即可完成图片缩放、格式转换等操作。
1 | # 使用 sips 调整图片尺寸 |
PS:如果你使用的是 Linux 或需要更复杂的图片处理,可以使用 ImageMagick 的
convert命令作为替代。
效果:32KB → 7.6KB,减少 76%
4. 修复 CLS 布局偏移
为 Logo 图片添加明确的尺寸属性:
1 | <img id="logo" src="/images/Logo_Sketch_88.png" width="50" height="50" /> |

第一轮优化后得分:47 → 61 分
第二轮优化:移除 Font Awesome
分析发现 Font Awesome CSS 体积约 19KB,加上字体文件更大,但我只使用了以下几个图标:
- ☰ 菜单图标 (fa-bars)
- ‹ › 分页箭头 (fa-angle-left/right)
- 社交媒体图标 (GitHub, YouTube, Bilibili 等)
解决方案:用 SVG 替换
1. 菜单图标
1 | <!-- 之前 --> |
2. 分页箭头
直接使用 Unicode 字符:
1 | <!-- 之前 --> |
3. 社交媒体图标
创建 SVG 图标映射对象:
1 | var svgIcons = { |
然后移除 Font Awesome CSS 引用:
1 | <!-- 删除这一行 --> |

第二轮优化后得分:61 → 94 分(移动端),100 分(桌面端)
为什么砍掉 Font Awesome 效果这么惊人?
这里的核心逻辑在于**”关键请求链(Critical Request Chain)”**的坍塌。
优化前:浏览器必须经历 HTML → style.css → all.min.css → fa-solid-900.woff2 的四级瀑布流。每一级都需要消耗一次完整的 RTT(往返时延),在移动端弱网下,这 2.4s 的延迟就是这样堆叠出来的。
优化后:SVG 直接内联在 HTML 字节流中。当浏览器解析到图标位置时,绘图指令已经就绪,请求链长度直接从 4 降到了 0。
当我打开浏览器的 Network 面板,看到 all.min.css 慢吞吞地去握手请求,随后又触发了两个一百多 KB 的字体文件下载时,我坐不住了。整个页面为了那几个分页箭头和菜单图标,足足白屏等待了 2 秒。
为什么我最终决定对 Font Awesome “动刀”?
在 Android 开发中,我们绝不会为了显示三个图标就集成一个几 MB 的 SDK。但在 Web 开发中,引入 all.min.css 似乎成了某种“默认操作”。
第三轮优化:SEO 与死链接修复
在追求性能的同时,我发现了一个被忽视的 SEO 问题:物理源码中的死链接。
1. 消除分页中的 /page/0/ 404 链接
很多 Hexo 主题(包括 Icarus)的分页组件在处理第一页和最后一页时,逻辑如下:
- 在第一页时,”上一页”按钮虽然被 CSS 设置为
is-invisible(视觉不可见),但 HTML 源码中依然生成了<a href="/page/0/">上一页</a>。 - 搜索引擎爬虫(如 Googlebot)是不会管 CSS 样式的,它会顺着
href爬取。由于/page/0/根本不存在,这会直接导致大量的 404 错误,拖累站点权重。
解决方案:组件本地化重写
我将分页组件 paginator.jsx 提取到本地,修改了渲染逻辑:
1 | // 修改前的逻辑:无论如何都生成 <a> |
2. 移除阻塞式的进度条组件 (Pace.js)
报告中显示 pace.min.js 是一个长链请求。虽然它能显示页面加载进度条,但:
- 它位于
<head>中,属于阻塞资源。 - 它对 LCP(最大内容渲染)没有任何帮助,反而占用网络带宽。
操作:直接在 _config.icarus.yml 中将其禁用。
第四轮优化:现代图片格式与自适应尺寸
在解决了代码和字体层面的问题后,PageSpeed Insights 的建议列表里只剩下了最后的”大块头”:图片资源。
报告指出,我的博客存在两个主要问题:
- 图片尺寸过大:例如 1536px 宽的封面图在手机上只显示为 ~360px,浪费了巨量带宽,直接拖慢了 LCP (最大内容渲染时间)。
- 格式老旧:仍在使用 JPG/PNG,而未利用压缩率更高的 WebP,错失了更好的压缩机会。
解决方案:自动化 WebP 转换与缩放
为了彻底解决这个问题,我编写了一个基于 nodejs sharp 库的自动化脚本,对全站主要图片进行了清洗:
1 | // 脚本逻辑摘要:自动化批量处理 |
具体优化案例
Ditherpunk 演示图 (
returnofobradinn)- 优化前:533KB (JPG)
- 优化后:~26KB (WebP, 672px)
- 体积减少:~95%。这对 LCP 的提升是决定性的。
文章封面图 (
esp32_dither_cover)- 优化前:1536x1587 resolution (533KB)
- 优化后:672x694 resolution (~28KB)
- 尺寸适配:严格匹配文章容器宽度 (672px),消除了 PageSpeed Insights 关于”图片尺寸过大”的警告。
M5Stack Cardputer 封面图 (
cardputer-streaming-cover)- 优化前:1200x900 resolution
- 优化后:600x450 resolution (~20KB)
- 针对显示区域较小的文章页,进一步将宽度限制在 600px 以匹配实际渲染尺寸 (599px)。
侧边栏缩略图
- 优化前:~20KB (原图缩小显示)
- 优化后:~3KB (WebP, 120px)
- 针对侧边栏的小图,特意生成了 120px 宽度的微缩版本,避免了大图小用。
网站 Logo
- 优化前:PNG 格式 (32KB)
- 优化后:WebP 格式 (8.1KB),且支持透明背景
进一步压榨:调整压缩因子
虽然转换到了 WebP,但默认的 80 品质对于某些大图来说仍然过剩。PageSpeed Insights 提示我们“提高图片压缩因子”。于是我又对生成的 WebP 图片进行了二次处理:
1 | // 使用 sharp 的极限压缩参数 |
这些细微的优化累积起来,最终让 LCP 分数直接拉满。
通过脚本批量处理,全站图片体积减少了 1MB 以上。
第五轮优化:消除关键请求链阻塞
在解决了图片和字体体积后,PageSpeed Insights 依然提示存在 441ms 的”关键请求链阻塞”。罪魁祸首是指向 fonts.googleapis.com 的 CSS 请求及其后续的字体文件下载。
虽然我们在第一轮优化中引入了本地 WOFF2 字体,但 Hexo 主题 (layout/common/head.jsx) 默认仍会加载 Google Fonts (Ubuntu, Source Code Pro)。
优化动作
- 移除 Google Fonts:直接注释掉主题中加载 Google Fonts 的代码。由于我们已经配置了本地字体栈 (Meslo LG / System Fonts),这一步是安全的,且直接节省了 441ms 的阻塞时间。
- 异步加载非关键 CSS:对于代码高亮样式 (
atom-one-light.css),它并不影响首屏内容的阅读(LCP 元素通常是标题或封面图)。我将其改为异步加载:
1 | <!-- 优化前:阻塞渲染 --> |
经过这一系列”手术”,关键请求链长度从 5 级降至 2 级,FCP (首次内容绘制) 时间大幅压缩。
优化成果总结
在编写这篇文章的期间, 一开始使用的主题是hexo-cactus-theme, 编写的过程中我切换到了hexo-icarus-theme.
刚切换到icarus时候,分数又回到了60以内, 但是经过本文描述的优化思路, 即使是首页展示图片而不是像cactus那也纯文字主页.
得分甚至来到了97分.
| 优化项 | 原始 (Icarus 默认) | 优化后 | 减少 |
|---|---|---|---|
| MesloLG 字体 | 636KB (TTF) | 160KB (WOFF2) | 75% |
| Logo 图片 | 32KB | 8.1KB | 74% |
| 图片资源 | JPG/PNG (大尺寸) | WebP (自适应尺寸) | > 90% |
| Font Awesome | ~19KB + 字体 | 0KB (内联 SVG) | 100% |
| Google Fonts | 441ms 阻塞 | 0ms (移除) | 100% |
| 资源预连接 | 无 | 4 个 preconnect | - |
| CLS 分数 | 0.339 | ~0 | - |
| PageSpeed 得分 | Icarus 初始 | 优化后 |
|---|---|---|
| 移动端 | 47 | 97 |
| 桌面端 | 67 | 100 |

经验总结
- 字体是大头:Web 字体往往是最容易被忽视的性能杀手,WOFF2 格式是首选
- 图标库要慎用:如果只用几个图标,内联 SVG 比加载整个图标库更高效
- 图片要按需:确保图片尺寸与显示尺寸匹配
- 预连接有用:对于必须加载的第三方资源,preconnect 可以节省 DNS + TCP 时间
- CLS 容易修复:给图片加上明确的尺寸属性即可避免大部分布局偏移问题
- 缓存生命周期 (TTL):除了资源体积,还可以通过 Cloudflare 等 CDN 强制开启静态资源的长期缓存(
Cache-Control: max-age=31536000)。这确保了用户在访问第二篇文章时,字体和 CSS 能从 Disk Cache 秒开,实现”瞬时”加载
工具推荐
- PageSpeed Insights - Google 官方性能测试工具
- WebPageTest - 更详细的瀑布图分析
- Squoosh - Google 的在线图片压缩工具
- ttf2woff2 - TTF 转 WOFF2 工具
希望这篇文章对你有所帮助!如果你也在进行网站性能优化,欢迎交流。
网站性能优化实战:PageSpeed Insights 从 47 分到 97 分的优化历程