这份指南不给 30 条技巧清单。
清单的问题不是没用,是没有顺序。同样一句「压缩图片」,在一个 TTFB 已经 1.2 秒的站上几乎没有意义;在一个 TTFB 180 毫秒、首屏却卡在 4 秒的站上,它可能就是全部的答案。技巧本身不带判断,判断来自测量。
所以这篇分四步走:先讲一次请求到底卡在哪一段,再讲怎么把这一段测准,然后给一张「症状对病因」的归因表,最后按层级给出改法与验证方法。
文中会出现我们自己站点的实测数据,作为样本。它是真实的、可复现的,也包含我们没做好的地方——文章页那张大图就是。
一、先把「慢」拆成四段
用户说的「慢」,在浏览器里是四个完全不同的东西。分不清这四段,后面的优化基本靠猜。
| 阶段 | 发生了什么 | 对应指标 | 谁负责 |
|---|---|---|---|
| 连接 | DNS 解析、TCP 握手、TLS 协商 | 无单独指标,计入 TTFB 前段 | DNS 服务商、线路、CDN |
| 首字节 | 请求到达服务器,PHP 执行、查库、拼 HTML | TTFB | 主机、PHP、数据库、缓存 |
| 渲染 | HTML 到达后,下载 CSS/JS/图片、布局、绘制 | FCP、LCP | 前端资源、图片、字体 |
| 交互 | 用户点击后,主线程处理事件并重绘 | INP | JS 体积、长任务、第三方脚本 |
四段是串联的,但不是等权的。TTFB 是天花板:服务器要 1.5 秒才吐出第一个字节,后面优化到极限,LCP 也进不了 2.5 秒。反过来,TTFB 压到 200 毫秒以内之后,前端每省 100 KB 都能直接反映在 LCP 上。
这条判断能帮你少做很多无用功:TTFB 没降下来之前,先别碰图片和 CSS。
还有第五个东西不在这条链上,但用户感知很强——CLS,页面加载过程中元素位置跳动。它不影响「多快看到」,影响「看得有多烦」,成因和上面四段没有关系,是布局预留问题。
二、测量:三种数据,三种用途
实验室数据不等于用户感受
PageSpeed Insights 给两个分数,很多人只看第一个。
- 实验室数据(Lighthouse):固定设备模拟、固定网络条件、单一地理位置、冷缓存。它的价值是可复现,适合改前改后对比。
- 现场数据(CrUX,Chrome 用户体验报告):真实用户在 28 天内的实际表现,取第 75 百分位。
Google 的排名判定用的是现场数据,不是你在自己电脑上跑出来的那个绿色 100 分。两者的差距可以很大:你的实验室 LCP 是 1.2 秒,而现场数据可能因为一批中低端安卓机 + 4G 网络,落在 3.8 秒。
第 75 百分位这个设定值得单独说一句。它意味着排在前 75% 的访问算「达标」,剩下 25% 的糟糕体验仍然计入评估——所以「大部分用户挺快的」不等于通过。三项 Core Web Vitals 要在 p75 上同时达到「良好」,整体才算通过。
官方阈值(2026 年现行)
| 指标 | 良好 | 需要改进 | 差 |
|---|---|---|---|
| LCP(最大内容绘制) | ≤ 2.5 s | 2.5–4.0 s | > 4.0 s |
| INP(交互到下次绘制) | ≤ 200 ms | 200–500 ms | > 500 ms |
| CLS(累计布局位移) | ≤ 0.1 | 0.1–0.25 | > 0.25 |
| FCP(首次内容绘制) | ≤ 1.8 s | 1.8–3.0 s | > 3.0 s |
| TTFB(首字节,实验性) | ≤ 800 ms | 800–1800 ms | > 1800 ms |
补充一句:FID(首次输入延迟)已经在 2024 年 3 月被 INP 取代,2026 年还拿 FID 当优化目标的教程,可以直接关掉。
服务器侧测量:curl 比截图可靠
前端工具告诉你「慢」,但不告诉你「哪一段慢」。用 curl 拆开看:
for i in 1 2 3; do
curl -s -o /dev/null --compressed \
-w "dns:%{time_namelookup}s tls:%{time_appconnect}s ttfb:%{time_starttransfer}s total:%{time_total}s size:%{size_download}B\n" \
"https://www.example.com/"
sleep 2
done
三个值分别对应:DNS 解析、TLS 握手完成、首字节到达。连续跑三次取中位数,单次结果没有参考价值——网络抖动、冷缓存、CDN 回源都会污染样本。
如果 time_starttransfer - time_appconnect 超过 500 毫秒,问题在服务器;如果只有 time_namelookup 高,那是 DNS;如果 time_total 远大于 time_starttransfer 而 HTML 只有几十 KB,那是带宽或线路。
我们自己的基线
下面这组数据来自本站,测试条件:1440×900 视口、Chrome 无缓存首次加载、单次取样、经代理访问(RTT 约 250 毫秒),因此 TTFB 包含线路延迟,不代表服务器纯处理耗时。
| 页面 | TTFB | LCP | 传输量(请求数) |
|---|---|---|---|
| 首页 | 335 ms | 824 ms | 357 KB(27 个) |
| 本页(优化前) | 175 ms | 356 ms | 268 KB(23 个) |
| 一篇技术长文 | 180 ms | 3,632 ms | 1,704 KB(34 个) |
三页的 FCP 分别是 808 / 340 / 352 毫秒,CLS 分别是 0.0015 / 0 / 0.0055。
需要说明的是,这些数字是在「禁用缓存 + 固定视口 + 固定网络」下取的。同一页面换个条件能差 10 倍:那篇长文在另一次测量里是 3.6 秒,因为浏览器缓存里已经有那张图,根本没发请求。测量条件怎么控制、p75 怎么读、指标怎么定位到具体元素,单独写了一篇 Core Web Vitals 怎么测才准。
三行数据放在一起,说明的问题比任何理论都清楚:TTFB 几乎一样(175–180 毫秒),LCP 却差了 10 倍。 差别不在服务器,第三行那篇文章的正文里有几张 300 KB 以上的 JPEG,最大的一张加载耗时 5 秒,它直接把 LCP 拖到了 3.6 秒。这几张图后来压过一轮(单张降到 200 KB 以内),这里保留压缩前的数据,因为它更能说明问题。
这就是为什么必须先归因再动手。
三、归因表:四种症状,四条路
拿到数据后,对照这张表定位,别上来就装插件。
| 症状 | 大概率原因 | 先查什么 | 去哪一节 |
|---|---|---|---|
| TTFB > 800 ms | 无页面缓存、PHP 版本旧、数据库慢、主机超售 | 关掉缓存插件前后对比 TTFB | 四、五 |
| TTFB 正常,LCP > 2.5 s | 首屏大图、字体阻塞、CSS/JS 阻塞渲染 | LCP 元素是什么、它几时开始下载 | 六、七 |
| LCP 正常,INP > 200 ms | JS 长任务、第三方脚本、过多事件监听 | Performance 面板找 >50 ms 的任务 | 七、十 |
| 指标都还行,CLS > 0.1 | 图片无宽高、字体切换、广告位动态插入 | DevTools 的 Layout Shift 区域 | 六、七 |
| 首页快,内页慢 | 内页无缓存、正文大图、评论/相关文章查询 | 分别测三类页面 | 五、六 |
一个常见误判:看到 PSI 分数低就去装缓存插件。如果瓶颈是首屏那张 400 KB 的 banner 图,缓存插件只会让 HTML 早到 200 毫秒,图片该多久还是多久,LCP 几乎不动。
四、服务器与主机层:TTFB 的天花板
TTFB 由四段构成:网络往返、nginx 处理、PHP 执行、数据库查询。前三段通常只占几十毫秒,大头在 PHP 和数据库。
先确认 PHP 版本
PHP 8.x 相对 7.4 有明显性能提升,这是官方基准测试就能看到的量级差异。很多站点慢,仅仅是因为还跑在 7.4 上。查一下:
php -v
# 或在 WordPress 后台 → 工具 → 站点健康 → 信息 → 服务器
如果版本低于 8.1,升级是投入产出比很高的一步。升级前必须做的一件事:在测试环境跑一遍所有插件和主题,PHP 8 对废弃函数的处理比 7.x 严格,老插件报错会直接白屏。
OPcache 有没有真的生效
OPcache 把编译后的字节码存在共享内存里,省掉每个请求的编译开销。装了不等于开了,开了不等于命中率正常。
php -i | grep -E "opcache.enable|opcache.memory_consumption|opcache.max_accelerated_files"
再看命中率(需要 opcache-status 或直接读 opcache_get_status()):
<?php
$s = opcache_get_status(false);
printf("命中率: %.1f%% 已缓存脚本: %d 内存使用: %.1f MB\n",
$s['opcache_statistics']['opcache_hit_rate'],
$s['opcache_statistics']['num_cached_scripts'],
$s['memory_usage']['used_memory'] / 1048576
);
命中率长期低于 95%,通常是 opcache.max_accelerated_files 太小(WordPress 加上插件动辄几千个文件,默认 10000 有时不够),或者文件修改时间校验开得太频繁。
PHP-FPM 进程数与内存
进程开太少,并发一上来就排队,TTFB 飙升;开太多,内存被吃满开始用 swap,更慢。经验算法:pm.max_children ≈ 可用内存 ÷ 单个 PHP 进程平均占用。一个跑 WordPress 的 PHP 进程常在 40–80 MB,2 GB 内存的机器给到 20–30 个子进程比较稳妥,具体要按实际 pmap 观察。
数据库
三条常被忽略的检查:
-- 慢查询是否开启
SHOW VARIABLES LIKE 'slow_query_log';
-- 临时表是否在写磁盘
SHOW STATUS LIKE 'Created_tmp_disk_tables';
-- 查询缓存(MySQL 8 已移除,别照旧教程配)
SELECT VERSION();
Created_tmp_disk_tables 占 Created_tmp_tables 的比例超过 25%,说明排序和临时结果集在落盘,通常是 tmp_table_size / sort_buffer_size 太小,或者有缺索引的慢查询。先开慢查询日志抓到具体 SQL,再谈调参——盲调缓冲区经常是负优化。
主机类型的真实差别
共享主机的问题不是「配置差」,是邻居不可控。同一台机器上另一个站被流量打满,你的 TTFB 就会跟着抖。云服务器自己管,自由度高但要自己配 PHP-FPM、OPcache、数据库;托管型 WordPress 主机把这些包好了,代价是单价高、可定制性低。
怎么选是另一件事,七款主流主机的横向对比在外贸WordPress服务器对比里有完整数据,这里只给一条判断:如果你连 SSH 都没有,别买云服务器自己配——默认配置的 LEMP 栈,TTFB 经常比共享主机还差。
已经自己配了的话,最容易配错的八个地方——上传目录能执行 PHP、敏感文件裸奔、真实 IP 丢失、open_basedir 与禁用函数、静态资源缓存漏配——WordPress 服务器安全里逐条给了症状、改法和验证命令。其中好几项同时也是 TTFB 的直接影响因素,配错了不只是不安全,还会慢。
五、页面缓存与对象缓存:收益更直接的一步
页面缓存解决的是「重复劳动」
WordPress 每次请求都要跑一遍 PHP:加载核心、插件、主题,查库,拼 HTML。一个没缓存的页面,这个过程通常 200–800 毫秒;命中页面缓存后,nginx 直接返回一个静态 HTML 文件,通常 10–50 毫秒。
这就是为什么页面缓存的收益通常大于其他所有前端优化之和——它砍掉的是整条服务器链路。
但页面缓存有明确边界:
| 场景 | 能否缓存 | 原因 |
|---|---|---|
| 未登录访客看文章/页面 | 可以 | 内容对所有人一致 |
| 登录用户后台 | 不可以 | 内容因人而异 |
| 购物车、结算页 | 不可以 | 依赖 session |
| 带 nonce 的表单页 | 需排除或特殊处理 | nonce 有时效,缓存会导致提交失败 |
| 多语言站的不同语言版本 | 可以,但要按语言分键 | 否则会串语言 |
最后一条踩过的人不少:缓存插件默认按 URL 分键,多语言插件如果靠 cookie 切语言,就会出现「访客看到中文缓存」的情况。
对象缓存解决的是「重复查询」
页面缓存对已登录用户、后台、以及未被缓存的页面完全无效。这时候起作用的是对象缓存:把数据库查询结果放到内存(Redis / Memcached),下次同样查询直接命中内存。
判断要不要上:看 wp_options 的 autoload 体积和每页查询数。查询数在 50 以内的站,对象缓存收益有限;超过 100 的,通常能砍掉一半以上的数据库时间。
本站启用了 Memcached 对象缓存,实测 autoload 数据如下:
SELECT COUNT(*) AS 条数, ROUND(SUM(LENGTH(option_value))/1024, 1) AS 体积KB
FROM wp_options WHERE autoload IN ('yes','on');
结果是 344 条、108.4 KB。这个体积意味着每个未命中页面缓存的请求,都要把这 108 KB 从数据库读出来并反序列化一遍。占用最大的几项:
| option_name | 体积 | 说明 |
|---|---|---|
| rewrite_rules | 17.2 KB | 固定链接规则,正常但偏大 |
| wpml_config_index | 15.4 KB | 多语言插件留下的配置索引 |
| image-sizes-docs-json | 9.4 KB | 插件文档 JSON,本不该 autoload |
| cx-plugin_docs_json | 9.4 KB | 同上,另一个插件 |
| wp_installer_settings | 6.8 KB | 安装器配置 |
最后三项是典型问题:插件的说明文档被标成了 autoload,每个请求都要背着它。这类项清掉(改成 autoload='no')没有功能风险,收益是实打实的。
经验阈值:autoload 总体积控制在 100 KB 以内比较健康,超过 300 KB 就该动手了。清理前务必备份数据库,并且逐项确认用途——rewrite_rules 这类不能乱动,删了会导致所有内页 404,重新保存一次固定链接才能恢复。
具体用哪个缓存插件、免费方案怎么组合,缓存插件横评里有七款的逐项对比;如果只是想搞清楚「改了东西为什么前台没变」,清除缓存没生效怎么查讲得更细。
六、图片与媒体:LCP 的主战场
LCP 元素十次有八次是图。所以图片优化的优先级高于 CSS 和 JS——但前提是 TTFB 已经正常。
图片有三个独立变量,任何一个没做好,另外两个白费。
变量一:格式
本站媒体库的真实构成:
| 格式 | 文件数 | 总体积 | 平均单张 |
|---|---|---|---|
| JPEG | 1,093 | 79.5 MB | 74 KB |
| PNG | 1,088 | 68.0 MB | 64 KB |
| WebP | 371 | 10.2 MB | 28 KB |
| GIF | 109 | 1.9 MB | 18 KB |
WebP 的平均体积是 JPEG 的 38%、PNG 的 44%。同一张图更能说明问题:本站首页团队图有两个版本,team3.webp 是 31 KB,而另一处引用的 team3.jpg 是 235 KB——同一张图,差 7.5 倍。
AVIF 比 WebP 再小一档,但编码慢、老设备兼容性要考虑。实用做法:WebP 做基线,AVIF 作为渐进增强(<picture> 里按顺序给 source)。
参数定在哪、批量怎么跑、只有 PHP 环境怎么处理,写在 WordPress 图片压缩:尺寸、格式与批量处理里;插件怎么选、怎么配,见图像优化插件推荐。
变量二:尺寸
最常见的错误是上传 2560px 宽的图,然后用 CSS 缩到 400px 显示。浏览器下载的还是 2560px 那份。
WordPress 5.3 起支持 srcset,会自动从媒体库生成多个尺寸,但有个前提:图片必须是通过媒体库插入的,且主题没有禁用 wp_calculate_image_srcset。手写 <img src="..."> 的图不会自动带 srcset。
检查方法:前台右键查看图片元素,看有没有 srcset 和正确的 sizes。sizes 写错(比如永远写 100vw)会让浏览器在小屏上也下载大图。
图片之外,视频是另一类常被低估的资源。同一段视频,自托管上传和封面图点击加载,对首屏的影响能差一个数量级,取舍与代码见 WordPress 添加视频:上传、嵌入与速度代价。
变量三:加载时机
<!-- 首屏主图:不要 lazy,给高优先级 -->
<img src="/hero.webp" width="1200" height="600"
fetchpriority="high" decoding="async" alt="...">
<!-- 首屏以下的图:懒加载 + 预留尺寸 -->
<img src="/content.webp" width="800" height="450"
loading="lazy" decoding="async" alt="...">
两个细节经常被写反:
- 首屏图加
loading="lazy"会拖慢 LCP。懒加载要等布局完成才触发下载,等于人为推迟首屏最大元素的加载。 - 不给
width/height会导致 CLS。浏览器不知道图片占多大地方,图加载完才撑开,下面的内容全部位移。现代浏览器会用宽高比自动预留空间,但前提是你写了这两个属性。
顺手能做的两件事
# 批量转 WebP(保留原图,输出到同目录)
find wp-content/uploads -type f \( -iname '*.jpg' -o -iname '*.png' \) -size +100k | while read f; do
cwebp -q 82 "$f" -o "${f%.*}.webp"
done
// 禁止 WordPress 生成 1536px 以上的超大尺寸(省磁盘也省 srcset 选项)
add_filter('big_image_size_threshold', function () { return 1600; });
插件方案(自动转换、CDN 侧转换、懒加载)在图像优化插件横评里有七款对比。手工方案的好处是可控,坏处是新增图片要记得跑一遍——如果团队里没人会记得,用插件更实际。
七、CSS、JS 与字体:渲染阻塞的真相
阻塞是怎么发生的
浏览器拿到 HTML 后,遇到 <link rel="stylesheet"> 会暂停渲染,等 CSS 下载并解析完才画第一帧。遇到没有 defer / async 的 <script> 会暂停解析 HTML,等 JS 下载并执行完才继续。
所以「CSS 文件多」和「JS 文件多」的代价不是字节数,是串行等待的轮数。HTTP/1.1 下浏览器对同域名只有 6 个并发连接,第 7 个资源要排队;HTTP/2 多路复用解决了排队问题,但没解决「必须等它下载完才能渲染」。
WordPress 特有的三个来源
- 插件各自 enqueue。装 10 个插件,可能带进 10 个 CSS 和 8 个 JS,其中大部分只在某个页面用得上,却全站加载。
- 区块编辑器样式。
wp-block-library这类文件在用了区块的页面上是必需的,但一些主题又额外加载了一套相似的样式。 - jQuery 依赖。很多插件声明依赖 jQuery,导致它在全站加载。jQuery 本身不大,但依赖链会拖出一串脚本。
具体手法
// 只在不需要的页面卸载区块库样式(谨慎:先确认页面没用区块)
add_action('wp_enqueue_scripts', function () {
if (is_front_page()) {
wp_dequeue_style('wp-block-library');
wp_dequeue_style('wp-block-library-theme');
}
}, 100);
// 给非关键脚本加 defer(不要对依赖 jQuery 的脚本盲加)
add_filter('script_loader_tag', function ($tag, $handle) {
$defer = ['some-non-critical-handle'];
if (in_array($handle, $defer, true) && strpos($tag, 'defer') === false) {
$tag = str_replace(' src=', ' defer src=', $tag);
}
return $tag;
}, 10, 2);
⛔ 三个不要:
- 不要全局禁用 jQuery。看着省了几十 KB,实际会让依赖它的插件静默失效,表单提交、轮播、弹窗逐个坏掉,而且不报错,排查成本极高。
- 不要用「合并所有 CSS/JS 为一个文件」的插件。HTTP/2 下收益很小,一旦某个文件出错整包失效,且缓存失效范围变大。
- 不要把所有图片都设成 lazy。首屏图 lazy 会直接拖慢 LCP。
字体
自定义字体有两个坑:FOIT(字体没到之前文字不显示)和 FOUT(先用系统字体显示,字体到了再换,造成跳动)。
@font-face {
font-family: 'BrandSans';
src: url('/fonts/brand.woff2') format('woff2');
font-display: swap; /* 先用后备字体,避免空白 */
unicode-range: U+0000-00FF; /* 只加载需要的字符集 */
}
再用 <link rel="preload" as="font" type="font/woff2" crossorigin> 预加载首屏用到的那一个字重。注意只预加载一个字重——预加载三个字重等于把字体变成阻塞资源。
中文站点还要算一笔账:一套中文字体动辄 3–8 MB,除非做子集化(只保留用到的字),否则不建议自托管中文字体,用系统字体栈通常更划算。
八、数据库与后台任务:不该被忽略的隐性项
这部分收益通常以几十毫秒计,不如页面缓存显眼,但它是每个请求都要付的固定成本。
修订版本
WordPress 默认每次保存都存一个修订。本站有 76 篇文章,修订版本 367 条——平均每篇 4.8 个。本身不算失控,但长期不清理会拖慢后台列表和数据库体积。
// 限制修订数量(写进 wp-config.php)
define('WP_POST_REVISIONS', 5);
-- 清理旧修订(先备份!先在只读环境跑一遍 SELECT 确认数量)
DELETE FROM wp_posts WHERE post_type = 'revision' AND post_modified < DATE_SUB(NOW(), INTERVAL 90 DAY);
自动加载项(autoload)
见第五节。这是数据库层最值得动的一处,因为它是「每个请求 × 108 KB」的固定税。
wp-cron 的假 cron
WordPress 的定时任务不是真定时,是「有人访问站点时顺带触发」。流量低的站,备份任务可能拖到第二天才跑;流量高的站,每个请求都可能触发一次 cron 检查。更麻烦的是,如果某个定时任务很重(比如全站备份),它会挂在某个真实用户的请求上,那个用户的 TTFB 就会异常高。
改成系统 cron:
// wp-config.php
define('DISABLE_WP_CRON', true);
# crontab -e,每 5 分钟跑一次
*/5 * * * * curl -s https://www.example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
别在高峰期跑备份和扫描
这一条不是技术问题,是排班问题。全站备份、恶意软件扫描、SEO 全站检查,都是重 IO 任务。安排在凌晨,或者至少避开你的询盘高峰时段。B2B 站的高峰往往在工作日上午,而很多主机的默认备份时间正好在凌晨 3 点——这个默认值还算合理,别改成白天。
九、CDN:什么时候值得,什么时候是心理安慰
CDN 解决三个问题:地理距离、静态资源分发、突发流量。它不解决 PHP 慢、数据库慢、前端臃肿。
判断要不要上,看一个数:你的访客离服务器有多远。
| 场景 | 上 CDN 的收益 | 说明 |
|---|---|---|
| 服务器在华东,访客 90% 在国内 | 低 | 物理距离近,回源延迟已经很低 |
| 服务器在国内,访客一半在欧美中东 | 高 | 跨洋 RTT 200 ms 起步,CDN 能砍掉大半 |
| 服务器在海外,访客在国内 | 高,但有风险 | 需选境内有节点的服务商,且要做备案 |
| 流量不大但经常被爬 | 中 | 主要价值是扛住爬虫和攻击流量 |
外贸站的典型情况是第二种:服务器在阿里云华东,客户在德国、美国、中东。这种站上 CDN 的收益非常直接——不是让 PHP 变快,是让静态资源不用跨洋取。
接入时注意四件事:
- 缓存规则。HTML 缓存时间设太长,改了内容前台不变;设太短,等于没缓存。常见做法:静态资源 30 天,HTML 按需(几小时到一天),后台和登录页不缓存。
- 回源 Host。配错会导致源站返回 404 或者跳到主域名,症状是「CDN 上的页面全白」。
- HTTPS。CDN 到源站这一段也要加密,否则中间可被劫持;证书要在 CDN 侧配好,并且和源站证书都别过期。
- 国内节点的合规要求。用境内 CDN 加速,域名需要备案。这一点经常被忽略,等到接入时才发现卡住。
还有一个现实问题:CDN 会隐藏访客真实 IP。如果站上有基于 IP 的限流、防爆破、地域封锁,接入后这些规则会全部失效——所有请求看起来都来自 CDN 节点。解决办法是在 nginx 里配 real_ip_header 还原真实 IP。这一步不做,安全策略等于开了个口子,具体配置在服务器安全那篇里有完整写法。
接入本身还有一整套顺序:缓存规则分几层、真实 IP 怎么还原、命中率怎么验证、哪些坑会让后台登不进去,另有一篇 WordPress 外贸站 CDN 指南专门讲。
十、主题与插件:性能在选型时就定了
上线之后再优化,能改的是配置和资源;改不了的是架构。而架构决定的性能上限,往往比配置大得多。
页面构建器的代价
可视化构建器(Elementor、WPBakery、Divi 这类)用嵌套 div 实现布局,一个首屏区块可能产生 15 层嵌套和上百个 DOM 节点。DOM 越深,样式计算和布局越慢,INP 越容易超标。
这不是说不能用,是说要知道代价:同样的设计稿,构建器产出的页面通常比手写模板重 2–4 倍。如果站点是给海外客户看的 B2B 官网,页面数量不多、设计要求高,构建器可以接受;如果是内容站,几百篇文章都要套同一套版式,手写模板更划算。
判断一个插件值不值得留
装之前测一次,装之后测一次,只看三个数:TTFB、请求数、页面传输量。
| 变化 | 判断 |
|---|---|
| 请求数 +5 以上,TTFB 无变化 | 可接受,但考虑按页加载 |
| TTFB +100 ms 以上 | 有问题,查它是否每次请求都查库 |
| 传输量 +200 KB | 有问题,通常是它全站加载了自己的 CSS/JS |
| 只在后台变慢 | 可接受,前端用户不受影响 |
一个常被忽略的点:停用的插件仍然占磁盘、仍然可能被扫描,但不影响前端性能。真正影响性能的是「启用但只在个别页面用」的插件——它们往往全站 enqueue 资源。这类插件值得单独处理,改成条件加载。
插件选型的方法论在B2B 外贸站常用的 8 个插件里有更系统的框架,这里只强调一句:插件数量本身不是问题,无条件加载才是。
十一、优化顺序:按这个顺序做,别跳
把上面的内容压成一张执行表。顺序很重要,因为前面几项会改变后面几项的判断。
| 阶段 | 动作 | 预期改善 | 风险 |
|---|---|---|---|
| 1. 摸底 | 测三类页面(首页/列表/文章)的 TTFB、LCP、请求数 | 无(但决定后面做什么) | 无 |
| 2. 服务器 | 升 PHP 8.x、开 OPcache、调 PHP-FPM | TTFB 降 30–60% | 低(需测试兼容) |
| 3. 缓存 | 页面缓存 + 对象缓存 + 清 autoload | TTFB 降到 100 ms 级 | 中(缓存规则配错会串内容) |
| 4. 图片 | 转 WebP、补 srcset、首屏图提优先级 | LCP 降 40–70% | 低 |
| 5. 前端 | defer 非关键 JS、卸载无用 CSS、字体 swap | LCP 再降 10–20%,INP 改善 | 中(容易连带坏功能) |
| 6. 架构 | 减插件依赖、换轻量主题、上 CDN | 长期维持 | 高(改动大) |
为什么服务器排在图片前面:TTFB 是 LCP 的组成部分。TTFB 500 毫秒的站,把首屏图从 400 KB 压到 40 KB,LCP 可能只从 3.2 秒降到 2.7 秒;而把 TTFB 压到 150 毫秒,同样的图能让 LCP 进到 1.8 秒。先砍固定成本,再砍变动成本。
为什么架构排最后:换主题、换插件、上 CDN 都是大改动,风险高、周期长。前面五步做完,多数站已经能进「良好」区间,第六步是否值得做,要重新评估。
⛔ 不要做的事:一次性把所有优化全上,然后发现网站坏了却不知道是哪一步导致的。一次只改一层,改完测一次。
十二、验证:怎么确认没白改
改完不清缓存就测,是最常见的自欺。页面缓存的机制决定了你看到的可能还是旧版本。
验证三件套
# 1. 清页面缓存(以 WP Fastest Cache 为例)
rm -rf wp-content/cache/all/*
# 2. 清对象缓存(Memcached)
echo "flush_all" | nc -w 1 127.0.0.1 11211
# 没有 nc 时用 PHP:
# php -r '$m=new Memcached();$m->addServer("127.0.0.1",11211);$m->flush();'
# 3. 用带随机参数的 URL 绕过页缓存,直测 PHP 真实输出
curl -s -o /dev/null -w "%{time_starttransfer}\n" "https://www.example.com/page?nocache=$RANDOM"
第三步是关键。裸 URL 命中静态缓存,测出来永远是 20 毫秒,看不出 PHP 改动的效果;带随机参数能强制走一遍完整流程,才是真实的服务端耗时。
上线检查清单
- □ TTFB 在目标区间(≤ 800 ms,理想 ≤ 200 ms)
- □ LCP 元素确认过是什么,且该元素已优化
- □ 首屏图没有
loading="lazy",且有width/height - □ 所有图片有
alt,非装饰图不报无障碍错误 - □
srcset生效,sizes不是固定100vw - □ 关键 CSS 内联或预加载,非关键 CSS 不阻塞
- □ 非关键 JS 有
defer,没有全局禁用 jQuery - □ 字体
font-display: swap,只预加载一个字重 - □ autoload 体积 < 100 KB
- □ 页面缓存规则排除了登录页、购物车、带 nonce 的表单
- □ CDN(如有)已还原真实 IP,限流规则仍生效
- □ 移动端在 4G 网络下实测过一遍,不只看桌面
回归:怎么防止慢慢变回去
性能不会一次优化就永久保持。装个插件、加个弹窗、换张 banner 图,指标就可能退回去。
务实的做法是设一个低频的自动检查:用 PSI API 每周拉一次核心页面的现场数据,或者干脆固定每周一手动跑一次 curl 三次取样,把数字记在一个表里。数字连续两周变差,就去查这周改了什么。
Google Search Console 的 Core Web Vitals 报告也能用,但它的更新有延迟(28 天滚动窗口),适合看趋势,不适合验证单次改动。
日常维护的节奏和检查项,WordPress 网站托管维护服务里按月、按季列了清单。
十三、常见问题
用了缓存插件,为什么还是慢?
三种可能:一是缓存没命中(登录状态、cookie、缓存规则排除了该页),二是命中了但 HTML 本身大(图片、内联 CSS、DOM 太深),三是 TTFB 快但 LCP 慢(渲染阶段的问题,缓存管不到)。先测「带随机参数的 URL」,如果它慢而裸 URL 快,说明缓存有效但源头慢;如果两个都慢,缓存根本没生效。
LCP 和 TTFB 是什么关系?
TTFB 是 LCP 的下限。LCP 计时从用户发起请求开始,包含 DNS、连接、等待首字节、下载资源、渲染。TTFB 500 毫秒,LCP 不可能低于 500 毫秒。所以 LCP 超标时,第一件事是看 TTFB 是否已经达标。
首页很快,内页很慢,为什么?
常见于三种情况:内页没被缓存规则覆盖(比如只缓存了首页和文章,没缓存分类页);内页正文有大图;内页模板触发了额外查询(相关文章、评论、面包屑)。分别测一遍,看是哪一种。
网站速度影响 SEO 排名吗?
Core Web Vitals 是 Google 页面体验信号的一部分,官方定位是「在内容相关性接近时起作用」,不是决定性因素。内容不相关,速度再快也排不上去;内容相当,速度差会吃亏。所以正确的心态是:把它当成及格线,不是增长手段。任何承诺「优化速度就能上首页」的说法都不可信。
图片压缩之后变模糊了怎么办?
先确认压缩质量参数。WebP 用 -q 80~85 通常在肉眼无差别;JPEG 用 75–80。如果原图本身分辨率就不够(比如 800px 宽的图放大到 1200px 显示),压缩只会更糟——这种情况要换原图,不是调参数。另外,文字截图和线条图不要用 JPEG,色块边缘会出现明显噪点,用 PNG 或 WebP 无损。
装了某个插件之后变慢,怎么定位?
停用它测一次,启用它再测一次,对比 TTFB 和请求数。如果 TTFB 明显上升,看它是否在每个请求都执行数据库查询(可以用 Query Monitor 看);如果请求数上升,看它 enqueue 了哪些资源、是否全站加载。确认是它的问题后,优先找「条件加载」的配置项,而不是直接换插件。
多久复测一次?
大改之后立刻测;日常每月一次;上新功能、换主题、加第三方脚本之后必须测。不要每天测——网络波动会让数据上下跳,反而干扰判断。
移动端和桌面端差很多,正常吗?
正常。移动端 CPU 弱、网络差,同样的页面 LCP 可能差 1–2 秒,INP 更容易超标。Google 的评估按设备类型分开算,所以移动端才是重点。测的时候别只在桌面 Chrome 里缩窗口,要用 DevTools 的设备模拟 + 网络限速,或者真机测。
十四、接下来做什么
如果只想做一件事:先测 TTFB。三次取样,超过 800 毫秒,其他都先放着,去查服务器和缓存。
如果 TTFB 正常但 LCP 超标:找出 LCP 元素是什么(DevTools → Performance → 勾选 LCP 标记),大概率是一张图,去压它。
如果两项都正常但页面还是「感觉慢」:多半是 INP 或 CLS,去 Performance 面板找长任务和布局位移。
这套流程不需要特殊工具,Chrome DevTools + curl + 一个能看数据库的工具就够了。真正的门槛不是技术,是愿不愿意先测再改。
我们自己做站也是按这个顺序来的。写这篇文章时顺手测了一遍,发现自己文章页的 LCP 是 3.6 秒——原因就是正文里几张没压缩的 JPEG。已经列进待办。这也说明一件事:性能优化不是一次性项目,是持续的习惯。
如果你的站已经排查过一轮但还是找不到瓶颈,或者不想自己动服务器配置,可以看看我们的建站与运维服务,或者直接把域名发过来,我们跑一遍同样的测量,把数据给你。