Hugo 静态网站图片加速:8.6MB 到 310KB 的实战记录

用 Hugo 内置图片处理管道把 8.6MB 的 PNG 背景图压缩到 310KB WebP,体积缩小 28 倍,弱网下加载从 5-10 秒降到 1 秒内。完整实操记录。

1. 为什么要做图片加速

静态网站加载卡顿,图片往往是最大元凶:

原因说明
图片体积大一张 2560×1440 PNG 可能有 8-10MB
格式低效PNG 无损压缩,适合截图但不适合照片
没有懒加载页面一次性加载所有图片
没有缓存每次访问都重新下载

核心思路: 让浏览器下载更小的文件。

2. Hugo 图片处理管道原理

Hugo 内置图片处理能力,构建时自动完成:

$$原始图片 (assets/img/wall4.png) ↓ Hugo 构建时处理 Resize "1920x webp q75" ↓ 优化后图片 (public/img/wall4_hu_xxx.webp)$$
操作语法说明
缩放Resize "800x"限制宽度 800px
裁剪Crop "800x600"裁成指定尺寸
填充Fill "800x600"填充并居中裁剪
转格式webp / jpg / pngWebP 体积最小
质量q7575% 质量(默认 75)

3. 方案一:CSS 背景图优化(实测)

步骤 1:图片放到 Hugo 资源目录

mkdir -p web-site/assets/img
cp 你的图片.png web-site/assets/img/wall4.png

步骤 2:创建处理 partial

新建 layouts/partials/hero-bg.html

{{/* Hero 背景图 — 用 Hugo 图片管道优化:转 WebP + 缩放到 1920px */}}
{{ $img := resources.Get "img/wall4.png" }}
{{ $webp := "" }}
{{ if $img }}
  {{ $webp = $img.Resize "1920x webp q75" }}
{{ end }}
{{ if $webp }}
<style>
  :root {
    --tn-hero-bg: url('{{ $webp.RelPermalink }}');
  }
</style>
{{ end }}

步骤 3:在页面模板中注入

在所有 baseof 模板的 <head> 里加一行:

<head>
  {{ partial "head.html" . }}
  {{ partial "hero-bg.html" . }}    <!-- ← 加这行 -->
</head>

步骤 4:CSS 里引用变量

.tn-hero {
  background:
    linear-gradient(rgba(18, 32, 88, 0.75), rgba(18, 32, 88, 0.85)),  // 遮罩
    var(--tn-hero-bg, url('/wall4.png')) center center / cover no-repeat;  // 背景图
}

步骤 5:重新构建

hugo
find public -name "*.webp"
# 输出类似:public/img/wall4_hu_8de1eac147519903.webp

4. 方案二:正文图片优化(shortcode)

markdown 里直接 ![](img.jpg) 不会走 Hugo 管道。写个 shortcode:

新建 layouts/shortcodes/img.html

{{ $img := .Page.Resources.GetMatch (.Get "src") }}
{{ $alt := .Get "alt" | default "" }}
{{ $width := .Get "width" | default "800x" }}

{{ if $img }}
  {{ $webp := $img.Resize (printf "%s webp q75" $width) }}
  <figure>
    <img src="{{ $webp.RelPermalink }}"
         alt="{{ $alt }}"
         loading="lazy"
         width="{{ $webp.Width }}" height="{{ $webp.Height }}" />
    {{ with .Get "caption" }}<figcaption>{{ . }}</figcaption>{{ end }}
  </figure>
{{ end }}

文章里使用:

{{< img src="photo.jpg" alt="产品图" caption="图1: 产品外观" >}}

注意: 图片必须放在文章同级目录(Page Bundle):

$$content/blog/我的文章/ ├── index.md ← 文章(注意是 index.md 不是 xxx.md) └── photo.jpg ← 图片和文章放一起$$

5. 方案三:懒加载

所有 <img> 加一个属性,浏览器滚动到才加载:

<img src="photo.webp" loading="lazy" />

正文图片用这个就够了,CSS 背景图懒加载需要 JS(IntersectionObserver)。

6. 效果验证方法

浏览器 Network 面板(推荐)

  1. 打开页面按 F12
  2. 切到 Network 标签
  3. 网络下拉选 Regular 3GSlow 3G
  4. 勾选 Disable cache
  5. Ctrl+Shift+R 强制刷新
  6. 看图片那行的 Time

curl 测速

curl -o /dev/null -w "耗时: %{time_total}s  大小: %{size_download} bytes\n" \
  http://localhost:1313/img/wall4_hu_8de1eac147519903.webp

实测对比

版本原始大小优化后Regular 3G 耗时
PNG 2560×14408.6 MB5-10 秒
WebP 1920px q75310 KB<1 秒

体积缩小 28 倍,弱网下加载从 5-10 秒降到 1 秒内。

7. 进阶技巧

7.1 多尺寸响应式(srcset)

根据屏幕宽度加载不同尺寸:

{{ $img := resources.Get "img/hero.png" }}
{{ $sm := $img.Resize "640x webp q75" }}
{{ $md := $img.Resize "1280x webp q75" }}
{{ $lg := $img.Resize "1920x webp q75" }}

<img src="{{ $lg.RelPermalink }}"
     srcset="{{ $sm.RelPermalink }} 640w, {{ $md.RelPermalink }} 1280w, {{ $lg.RelPermalink }} 1920w"
     sizes="100vw"
     loading="lazy" />

7.2 更激进压缩

$img.Resize "1920x webp q50"   // 50% 质量,体积更小
$img.Resize "1920x webp q30"   // 30% 质量,适合纯色背景图

7.3 Nginx 缓存

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

7.4 CDN

  • Cloudflare:免费套在网站前,自动缓存 + 压缩
  • jsDelivr:GitHub/Gitee 仓库静态资源免费 CDN

总结

$$1. 图片放 assets/ 目录 2. 用 resources.Get + Resize "xxx webp q75" 处理 3. CSS 背景图 → 注入 CSS 变量 4. 正文图片 → 自定义 shortcode 5. 加 loading="lazy" 6. 浏览器 DevTools 验证速度$$