博客上线那会儿,我发给朋友看,朋友回了一句:“你的站怎么转半天才出来?“我自己在美国打开觉得还行,可朋友在国内,点开一篇文章,封面图要等好几秒。我查了一下:一张手机直出的原图就有 2–4MB,文章列表页一次加载 10 张封面,全是原图的话就是几十 MB,不慢才怪。

那之后我把加速这件事认真做了一遍。结论先说在前面:静态博客的加速,八成功夫都在图片上,剩下的才是懒加载和 CDN。三件事做完,单张封面压到 60–300KB,/posts/ 列表页 10 张图合计约 1MB,打开速度肉眼可见地变快。这篇就是实操记录,照着做就行。

先测再动:慢在哪儿,得有数

动手之前先测速,不然你都不知道自己在修什么。我常用的就两个免费工具:

PageSpeed Insights(Google 出的)。输入网址,等半分钟,给出手机端和桌面端的分数,还有 LCP(最大内容绘制时间)这种核心指标。分数不用追求满分,90 分以上就挺好了。

GTmetrix。能看到每个资源的加载时间,一眼看出是哪张图、哪个 JS 在拖后腿。

拿 PageSpeed 测,报告里最显眼的一项就是图片:几张封面图单张 2–4MB,全在打开时一起下载。问题定位了,再动手。

顺便说一句:测速多测两次,取个平均。网络波动大,单次结果别太当真。

图片压缩:八成功夫都在这儿

图片是静态博客最大的负担,没有之一。我的处理标准很简单:

最长边 1600px,JPEG 质量 80 左右。 博客封面图在页面上显示也就 800px 宽,1600px 的原图在视网膜屏上也够清晰了。再大,就是纯浪费流量。一张手机直出的 4000px 照片,4MB 左右,压到 1600px、质量 80,基本在 150–200KB,体积直接砍掉 95%。

我用的工具分两种情况:

批量处理用命令行。 服务器上有 ImageMagick 的话,一条命令搞定一个文件夹:

mogrify -resize 1600x1600\> -quality 82 -strip *.jpg

-resize 1600x1600> 的意思是只缩小不放大,小图不会被强行拉大;-strip 去掉 EXIF 信息,又能省一点,还能顺手去掉拍照地点这些隐私信息。

单张精修用 Squoosh(Google 的免费在线工具)。拖进去,拉动质量滑杆,实时看压缩前后的对比,满意了再下载。封面图这种门面,值得花一分钟精修。

WebP 要不要上? WebP 同样画质下比 JPEG 小 25%–35%,听着很香。但我的做法是:封面图先用 JPEG 保证兼容性,等全站图片都压完了,再考虑统一转 WebP。饭一口一口吃,别为了追极致把自己绕进去。Hugo 自带图片处理功能,模板里用 .Resize 就能自动生成多尺寸,需要的话以后再上。

我把 40 篇的封面图全量压了一遍,压完后总计约 4MB。单这一项,文章页和列表页的加载时间就砍掉大半。如果你只想做一件事,就做这个。

懒加载:首屏之外,别急着加载

图片压完了,还有个问题:/posts/ 文章列表页一次列出 10 篇文章,10 张封面图全在打开瞬间一起下载,哪怕每张只有 150KB,加起来也是 1.5MB。用户可能只看前两篇,下面的图白下载了。

解法是懒加载(lazy loading):图片进入视口之前不加载,滑到哪儿加载到哪儿。现代浏览器原生支持,一行属性就行:

<img src="cover.jpg" loading="lazy" alt="封面图">

Hugo 的 PaperMod 主题里,文章列表的封面图可以加上这个属性;正文里的图片,Hugo 0.110 之后可以用 Markdown 渲染钩子(render hook)统一加:

<!-- layouts/_default/_markup/render-image.html -->
<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}"
  {{ with .Title }}title="{{ . }}"{{ end }} loading="lazy">

放一个文件,全站正文图片自动懒加载,不用每篇手动改。

注意一个例外:首屏第一张图别懒加载。 首屏图是 LCP 的主角,懒加载反而拖慢它的显示。文章页顶部的封面保持正常加载;列表页和正文里的其他图片再懒加载。

CDN:套一层 Cloudflare,免费的就够

图片压完了、懒加载上了,最后一块是网络距离。我的服务器在美国菲尼克斯,国内读者访问要跨太平洋。静态博客的好处是全站都是静态文件,特别适合 CDN 缓存——CDN 节点帮你把文件存在离读者近的地方,读者不用每次都跨洋取文件。

我用的就是 Cloudflare 免费版,配置很简单:

  1. 域名 DNS 接管到 Cloudflare(我的站早就是这么跑的)。
  2. 开启代理(小云朵变黄),流量就走 Cloudflare 的节点。
  3. 缓存规则里把图片、CSS、JS 的缓存时间设长一点,比如 30 天——静态文件不常变,缓存久一点没关系;HTML 页面缓存时间短一点,或者不缓存,保证新文章及时出来。

效果上,国内读者打开文章页,图片基本从就近节点返回,不用再跨太平洋。配合前面两步,列表页和文章页的加载都会轻不少。

一个提醒:上 CDN 之后改了东西要记得清缓存。 发了新文章、换了封面图,首页可能还显示旧的。Cloudflare 面板里可以按 URL 清缓存,养成习惯:每次部署完顺手清一下首页和改过的文章页。

另外,如果你的读者主要在国内,Cloudflare 免费版的国内节点覆盖一般,速度提升有限,但总比没有强。真要极致,可以再套一层国内 CDN,不过那就要备案了,是另一个话题。

Nginx 侧:三行配置,别漏了

服务器这边也有三件小事值得做,我的 Nginx 配置里都有:

开 gzip 压缩。 HTML、CSS、JS 这些文本文件,gzip 能压掉 70% 左右。图片已经压过了,gzip 不管图片,只管文本:

gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
gzip_min_length 1024;

设缓存头。 告诉浏览器:图片、CSS、JS 可以本地缓存 30 天,下次打开直接读本地,不用重新下载:

location ~* \.(jpg|jpeg|png|webp|css|js)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

确认 HTTP/2 开了。 Nginx 配了 HTTPS 之后,listen 443 ssl http2; 这一行别漏,多路复用对图片多的页面提升很明显。

这三项加起来也就十来行配置,搭站那篇里的 Nginx 配置就是我的底子,在这个基础上加就行。

验收:别凭感觉,拿数字说话

做完这几步,重新测一遍。我这边能拿到的实测数字是这些(2026-11-04 刚量的):已上线的封面图,银行开户那篇约 300KB、看牙那篇约 60KB、找室友那篇约 80KB;/posts/ 列表页 HTML 约 27KB,10 张封面合计约 1MB。发布后拿 PageSpeed 再跑一次,重点看 LCP 和手机端分数,跟改之前对比一次,心里就有数了。

还有一个实测发现:AdSense 的广告脚本 adsbygoogle.js 单文件就 206KB,每个文章页都会加载——这是接广告的代价,压图片省下来的体积,有一部分会被它吃回去。接受它,但别再往页面上加别的重型脚本了。

数字供参考,你的站情况不同,结果也会不同。但方向是一样的:图片最大头,懒加载第二,CDN 第三,Nginx 配置是收尾。

最后留一个检查清单,每次发新文章前过一遍:

  1. 封面图压到最长边 1600px 了吗?
  2. 图片加懒加载了吗(首屏那张除外)?
  3. 部署完清 CDN 缓存了吗?
  4. 手机上打开看一眼,首屏 2 秒内能出来吗?

加速这件事没有终点,但做到这一步,对个人博客来说已经够用了。再往下就是图片 CDN 分片、预加载字体这些边际收益越来越小的活儿,留着以后慢慢折腾。建站选型那篇里我说过选 Hugo 是图它快、图它省心——快这个优点,值得花一个下午把它兑现。

PaperMod 主题配置那篇里提过,主题本身对中文支持不错,但速度优化还得自己动手。主题给的是底子,性能是你自己的活儿。