为什么各种平台的页面在 PageSpeed 上都分数难看——以及为什么"分数"本身就是错的指标
这几年我一直在做 Next.js、Prismic、Shopify、WordPress 站的性能。这篇文章是我弄明白的一件事:为什么这些数字永远对不上——以及我最后到底报的是哪几个数。
#几乎每个项目上,我都会被问同一个问题
有客户问我:"为什么我们的分数这么低?"
那个站用起来是快的。看起来也快。我自己笔记本上跑 Lighthouse,98 分。
PageSpeed Insights 说 71 分。
两个数字都没错。但有两件事没人告诉过他:
- 这两台仪器测的根本不是同一件事。
- 分数不是你网站的属性,它是一次读数——在某台机器上、某个网络下、某一刻取的。
第二条,是我现在会先说出口的那一条。
#一、你测的到底是什么
本地 Chrome 的 Lighthouse 和 PageSpeed Insights,有四个变量在同时变化:
- 网络。 本地:你家宽带,通常还带缓存。PageSpeed:固定 Slow 4G。
- CPU。 本地:你自己的机器。PageSpeed:4 倍 CPU 节流。
- 缓存。 本地:很容易保持热缓存。PageSpeed:每次冷启动。
- 地理。 本地:通常离 CDN 很近。PageSpeed:Google 机房 → 你的主机,TTFB 更差。
同一个页面,98 和 71。这个差距不是哪个工具的 bug——是四个变量同时在变,而只有一个是你的代码。
我的做法:我报任何一个数字,都会说清它是哪个工具、哪个配置跑出来的。缺了这个上下文的数字不是信息。
#二、我见过三种"测错了"
在 dev 服务器上测。 npm run dev 不压缩,还在跑热更新循环。我在一个生产环境 80 多分的页面上,测出过移动端 约 52 分。那不是基线,那是噪声。
在已经访问过的浏览器里测。 你的缓存替访客挡掉了他们必须付的代价。开无痕、关缓存,否则别信那个数。
测了一个已经被替换掉的部署。 你改了代码——但你测的 URL 是上一版构建。用预览部署的时候,这件事天天发生。
我的做法:动手之前,我先把工具、配置、URL、构建版本写下来。我被叫去修的"性能回退"里,有一半其实是这三种情况之一。
#三、为什么各种平台的页面分数都难看
我做的是四种技术栈,它们的坏法各不相同。但底层病因是同一个:
这些平台,每一个都允许"不是你写的代码"跑在你的关键路径上。
Shopify——第三方脚本主宰分数。 在 Shopify 上,主题很少是问题本身。预约、评论、客服、热图、像素——它们都是运行时注入,并且占着主线程。
我手上最清楚的一个例子:一个预约 App 从 Google CDN 拉 jQuery。弱网下那个请求变慢或直接失败,按钮就永远停在"Loading…"。修的地方不在 App 里,而在主题侧:
- 把 jQuery 自托管进主题,在产品模板上提前加载
- 对 App 的 CDN 加 preconnect
- 关掉移动端挡住弹窗的吸底加购按钮
- 修掉弹窗的 z-index 和滚动锁
而复现方式比修法更关键:那个"按钮消失"只在弱网下、从列表页跳进详情页时才出现。单独测列表页,什么都证明不了。
我的做法:Shopify 上我测那个"脚本真正注入的页面",而不是那个"方便测的页面"。
WordPress——插件堆积。 邮件、礼品卡、表单、支付,每一样都带自己的前端 JS 和 CSS,堆起来比谁预想的都快。缓存还是陷阱:登录态、购物车、结账页通常绕过缓存,所以两种状态我都测,并且说清报的是哪一种。
Next.js 和内容型站点——三个惯犯。 同一个资源被下载两次(一个只在手机显示的 <img> 加一个只在桌面显示的 <img>,同一个文件);一个 CSS background-image 要等样式表解析完才被发现;首屏包里的 JavaScript 太多。
我的做法:内容型站点我第一个问题永远是——LCP 那个元素,在初始 HTML 里能被发现吗? 我遇到的最慢的那些案例,答案都是"不能"。
#四、分数到底扣在哪
Lighthouse 10 的性能权重大致是:
- TBT——约 30%。 主线程被长任务阻塞。
- LCP——约 25%。 最大元素渲染太晚。
- CLS——约 25%。 布局跳动。
- FCP——约 10%。 首次内容绘制。
- SI——约 10%。 视觉完整速度。
TBT 加 LCP,超过一半。 所以有人让我"修一下性能",我就做这两个,而且我会直接说出来。整周去抠 FCP 和 Speed Index,是在处理 20% 的问题。
而且我都在移动端做。桌面分数看起来都正常,正好把这些问题全遮住。
#五、两个到现在还会让人意外的点
纯色背景不算 FCP。 首次内容绘制需要真正的内容——文字、图片、渐变、SVG。整页只刷一个背景色,它就没有首绘,不管看起来多好看。
font-display: optional 能帮你赢下 CLS 和 LCP——在网速好的时候。而在慢网下,整次访问都会停在兜底字体上。在客户眼里那不是"我选的权衡",那是个 bug。
#六、不舒服的那部分,我现在会提前说
这是一个真实项目上的数字链,按顺序:
- 本地宽带 Lighthouse:最高 98
- PageSpeed Insights 移动端:71–75
- 临时压缩图片:约 91——客户以"变模糊"为由否掉
- 恢复高清图:稳定在 82–85
所以现在项目一开始我就把这句话说掉:
如果"不降画质、不改结构"是硬要求,移动端分数很少能锁在 90。
总得让一样东西:体积、动效,或者图片。我的工作就是告诉你我会放弃哪一样、代价是什么。如果没有人就这个达成一致,我们会永远为分数争论——而分数恰恰是那个取决于它在哪台机器上被测的数字。
#七、那我都报什么
我不再把分数当目标。它只是一个依赖环境的读数。
页面体积和 LCP 是页面本身的属性。 它们能跨环境走——Google 测和我测,是同一个值。所以我测这两个,给同一台机器上前后紧挨着测出来的对比。
分数告诉你:某台机器、某个网络,对你的页面是什么感觉。
页面体积和 LCP 告诉你:你的页面实际上是什么。
#八、三步,你自己就能验
- DevTools → Network → Img,刷新。 找最大的那张图,把文件的真实宽度和它实际显示的尺寸比一下。文件是渲染尺寸的 2–3 倍,你的第一个收益就在这——而且通常是最便宜的那个。
- 移动端 Lighthouse 跑三次,报中位数。 永远不要只跑一次。只跑一次等于抛硬币。
- 在你 HTML 里搜两个指向同一个文件的
<img>标签。 那就是重复下载,修它不花钱。
#一句话版本
测生产环境,别测 dev 服务器。让 LCP 元素能被发现、只请求一次。把首屏的 JavaScript 和字体从关键路径上挪开。记住纯色不算 FCP。Shopify 的 App 要在它真正加载的那个页面测。在你向任何人承诺数字之前,先把画质上的取舍谈清楚。
我做内容驱动站点的前端——Next.js、Prismic、Shopify、WordPress——并且把结果测出来,而不是口头断言。想知道你的站是真的慢,还是只是被测坏了,把它丢进 prismicaudit.com,把结果发我。