本文约 4,552 字,预计阅读 12 分钟。文中命令与配置均经过实测,可直接参考执行。
引言:换了个主题,速度到底变好了还是变坏了
不少站长判断主题快慢靠“体验一下”。这种方法在本地 SSD + 千兆宽带 + 浏览器缓存的环境里完全失效:一切都很快。真正有意义的是三个可复现的数字——首屏请求数、关键路径资源体积、服务器响应耗时(TTFB)。
这三个数字对应三种完全不同的优化方向:请求数多是小文件太多或合并缺失;体积大往往是图片/字体/实际并未用到的库;TTFB 长则是后端问题(autoload、慢查询、缓存缺失)。主题本身的“体积”这个词其实同时跨越了三个层面:磁盘上的包大小、传输时的字节数、以及浏览器要解析执行的成本。
本文把三者分开测量,每一步都给你一个可以直接复制的命令。测量前建议先读一遍插件与主题功能重复时的处理原则,因为重复的资源引入往往是体积失控的第一步。
原理分析:三个数字分别由什么决定
首屏请求数 = HTML 文档 + CSS + JS + 图片(首屏可见部分)+ 字体。它的影响在低带宽高延迟的网络里被放大:每多一个请求,就多一次 RTT。HTTP/2 的多路复用缓解了这个问题,但并不能让它消失——尤其是存在跨域名请求时还要额外握手。
传输体积 不等于磁盘体积。磁盘上 800 KB 的主题,经过 gzip/brotli 后 CSS/JS 通常只剩 1/4 左右;真正难以压缩的是图片和字体。所以看磁盘大小意义有限,要看 Content-Length。
TTFB 由服务端决定:主题自己的 functions.php 执行时间、wp_options autoload 读取、模板里额外的 WP_Query 都会算进去。很多号称“轻量”的主题在 TTFB 上翻车,原因往往是模板文件里的重复查询而非资源体积。
保姆级实操
第一步:测磁盘基准(区分“主题本体”与“演示数据”)。
cd wp-content/themes/候选主题/
# 主题总体积(含所有 options / fonts)
du -sh .
# 排除 demo / sample / assets-lightbox 之类目录后的真实本体体积
du -sh --exclude="*demo*" --exclude="*sample*" .
# 按类型拆分统计:哪些才是大头
find . -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn | head -12
第二步:测传输体积(这才是用户真正下载的字节)。
# 取单个资源的压缩后大小
curl -sI -H "Accept-Encoding: gzip, br" https://example.com/wp-content/themes/主题/style.css \
| grep -i "content-length\|content-encoding"
# 若服务器已开启 brotli,可对比两者差异
curl -s -H "Accept-Encoding: br" -o /tmp/style.css.br -w "br传输=%{size_download}\n" \
https://example.com/wp-content/themes/主题/style.css
curl -s -H "Accept-Encoding: gzip" -o /tmp/style.css.gz -w "gzip传输=%{size_download}\n" \
https://example.com/wp-content/themes/主题/style.css
第三步:统计一个页面的首屏资源清单。
# 从首页 HTML 里抽取所有外链资源,去重后计数
curl -s https://example.com/ \
| grep -oE '(src|href)="[^"]+\.(css|js|woff2?|png|jpe?g|webp)"' \
| sed -E 's/.*="//; s/"$//' | sort -u > /tmp/assets.txt
echo "首屏资源总数: $(wc -l < /tmp/assets.txt)"
awk '{print $0}' /tmp/assets.txt | sed 's/.*\.//' | sort | uniq -c | sort -rn
把得到的清单按域名分组,就能看出有多少来自 wp-content/themes/、多少来自 plugins、多少是 CDN/外部字体。
第四步:用 wp profile 拆解 TTFB 属于哪个阶段。
wp package install wp-cli/profile-command
wp profile stage --fields=stage,time,cache_ratio --spotlight
输出会按 bootstrap、build_query、wp_head、loop、template 等阶段给出耗时。若 template 阶段占比异常高,说明主题模板文件里有重活;若 bootstrap 高,通常是 autoload options 或 mu-plugin 的问题。
进一步定位到 hook:
wp profile hook wp_head --fields=callback,location,time --spotlight
wp profile hook template_redirect --fields=callback,location,time --spotlight
第五步:确认压缩与缓存是否真的生效。
# nginx 侧建议的最小配置
gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
# 若模块可用,brotli 对 CSS/JS 的压缩率明显更高
brotli on;
brotli_comp_level 5;
brotli_types text/plain text/css application/javascript application/json image/svg+xml;
# 静态资源长缓存(配合文件名版本化使用)
location ~* \.(css|js|woff2?)$ {
expires 180d;
add_header Cache-Control "public, immutable";
}
# 验证是否生效
curl -sI -H "Accept-Encoding: gzip" https://example.com/wp-content/themes/主题/style.css | grep -i "content-encoding\|cache-control"
第六步:建立长期基线。
把上面的测量写成一个脚本,每次主题/插件变更后跑一遍,输出三行数字:请求数、传输总字节、TTFB 阶段分布。
#!/usr/bin/env bash
# theme-bench.sh —— 主题体积基线测量
SITE="https://example.com/"
echo "== $(date '+%F %T') =="
curl -s "$SITE" | grep -oE '(src|href)="[^"]+\.(css|js|woff2?|png|jpe?g|webp)"' \
| sed -E 's/.*="//; s/"$//' | sort -u | wc -l | xargs echo "首屏资源数:"
curl -s -o /dev/null -w "TTFB=%{time_starttransfer}s 总计=%{time_total}s 体积=%{size_download}B\n" "$SITE"
wp profile stage --fields=stage,time --format=table 2>/dev/null | tail -n +1
常见踩坑
- 只看
du -sh就下结论。压缩后的 CSS/JS 通常只有磁盘体积的 20–30%,图片才是不可压缩的大头。 - 在本机浏览器里测。浏览器缓存、扩展脚本、本地 DNS 都会让结论失真,用
curl或干净的 Lighthouse 容器。 - 没有考虑 HTTP/2/3 的差异。相同请求数在不同协议下成本不同,测试环境的协议要与生产一致(用
curl -sI --http2确认)。 wp profile在生产环境高负载时跑。会使站点进一步变慢,建议在低峰或克隆环境执行。- 统计请求数时漏算内联
@font-face和 CSS 里引用的图片。这些也属于首屏请求。 - 开了
immutable长缓存却没做文件版本化。CMS 更新文件内容但 URL 不变,用户会一直拿到旧版本。 - 案例:某站以“主题只有 600 KB”为由选了一款轻量主题,上线后移动端依然慢。用上面的
wp profile stage一测,template阶段占了 480 ms——原因是主题为了显示“相关文章”,在 single.php 里跑了三次独立的WP_Query,其中一次还带meta_query。把三次查询合并为一次并加 transient 缓存后,TTFB 直接降到 190 ms。磁盘体积小 ≠ 运行开销低,模板里的查询才是隐藏成本。
总结
评估一个主题,请固定输出这三个数字:首屏请求数(目标 ≤ 20)、TTFB(目标 ≤ 300 ms)、传输体积(目标 ≤ 800 KB)。达不到就按归因处理:请求数多 → 合并/延迟加载/内联关键 CSS;体积大 → 压缩 + 图片 WebP + 字体子集化;TTFB 高 → 查 wp profile 的阶段分布,把最耗时的阶段当单点问题处理。
别忘了把这里的分项数据和插件对 Core Web Vitals 的影响测量里的归因方法交叉验证。最后一个建议:把 theme-bench.sh 加进你的发布流程(上线前后各跑一次)。有了连续数据,任何一次主题更新带来的性能回退都会立刻被看见,而不是等到用户抱怨。
