今年 8 月我们接手一个 SaaS 官网的性能整改,移动端 LCP 4.6 秒,六周后稳定在 1.9 秒。中间没有换服务器,也没有重写前端。六件事按性价比排下来,顺序比技术选择更重要。
这个站的情况挺典型:Next.js 做的营销站,首屏传输 2.8MB,42 个请求,第三方脚本 9 个。老板的原话是"我们的页面怎么这么慢",但没人知道慢在哪。我们先跑了一轮真实的移动端测试,不是本地开 DevTools 看,而是用 4G 模拟加 CPU 4 倍降速。
第一件:首屏传输从 2.8MB 压到 740KB
图片占 1.6MB。hero 图、六张客户 logo、一张 dashboard 截图,全是 PNG。换成 WebP,按容器尺寸出 2 倍图,logo 改 SVG。这一步单独把 LCP 从 4.6 秒带到 3.2 秒。
顺带一个细节:他们 logo 墙用了六张 400×400 的 PNG,实际渲染 32×32。这种浪费在软件站特别多,客户 logo 是市场部从 PPT 里导出来直接上传的。
第二件:砍掉三个阻塞渲染的请求
头部有一个字体 CSS、一个图标库 CSS、一个没用上的组件库样式,合计 210KB,全是同步加载。字体改自托管加 preload,图标库换成内联 SVG 只留用到的 14 个,组件库样式按需引入。LCP 到 2.7 秒。
第三件:中文字体换子集
他们的中文主字体是 3.4MB 的思源黑体全量包,font-display 没设。改成常用 3500 字的子集,280KB,font-display: swap。中文软件站这一步几乎必做,代价小,收益稳定。
第四件:第三方脚本全部延后
9 个第三方里,客服组件、两个统计、一个 AB 测试、一个热力图,首屏一个都不需要。改成用户首次交互后再加载,首屏请求从 42 降到 19。LCP 到 2.1 秒。
第五件:给首屏图提优先级
hero 图加 fetchpriority="high",同时在 head 里 preload。这一步单独看收益最小,但在 2.1 秒的基数上,它挤出了最后的 0.2 秒。
第六件:HTML 走边缘缓存
营销页内容一周改一次,没必要每次回源。在 CDN 上给首页和定价页设了 10 分钟缓存加 stale-while-revalidate,TTFB 从 620 毫秒降到 140 毫秒。
顺序比技术重要
六件事如果倒过来做,先上 CDN 再优化图片,效果要差一半。我们判断顺序的标准很土:这一步能不能减少字节或者减少阻塞,能就优先。优先级调整和缓存策略属于锦上添花,放在最后。
还有个反常识的点:这个站做完 PSI 分数从 31 到 88,但自然流量第三周才开始动,第六周涨了 23%。速度是必要条件,不是充分条件,别指望改完性能排名第二天就往上走。
过程中踩的三个坑
第一个坑是 preload 加重复了。前端在 head 里加了 preload,组件里又自己加载一次,同一张图下载两遍,移动端多花了 400 毫秒。排查方法是在网络面板里按文件大小排序,看到同一 URL 出现两次就明白了。
第二个坑是缓存把改动盖住了。图片换完,CDN 上还是旧版本,测了两天都是 4.1 秒,差点以为方向错了。现在我们的规矩是每次改静态资源都带版本号或者刷新缓存。
第三个坑是只测了首页。首页做到 1.9 秒,客户很满意,结果产品页、文档页还在 5 秒以上。营销站真正的入口是产品页和文档,首页只占访问量的三成。这批页面后来单独做了一轮,又多花了两周。
元析智能
为软件公司做 SEO 和 GEO 优化