web-vitals-cn
name: web-vitals-cn
description: 国内网络环境下的 Web 首屏与性能优化。当页面打开慢、LCP 差、白屏时间长、移动端卡顿、字体闪烁、或者要在弱网和国产浏览器上提速时使用。触发词:首屏慢、白屏、LCP、CLS、INP、Web Vitals、打包体积大、加载慢、CDN、字体加载、图片优化、弱网、性能优化。不负责后端接口性能(走 mysql-slow-query 或 go-service-release)。
国内网络下的前端性能优化
国内的性能优化和海外教程有几处关键差异:Google Fonts 和多数海外 CDN 不可用或极慢、运营商链路质量差异大、安卓中低端机占比高、微信内置浏览器(X5/XWeb)行为特殊。照抄海外最佳实践会踩坑。
一、先测量,别猜
三层数据缺一不可:
- 实验室数据:Lighthouse / WebPageTest。用来定位问题。
- 真实用户数据(RUM):用
web-vitals库上报 LCP、INP、CLS,按机型、网络、地区切片。这才是判断依据,实验室数据经常和真实差一个量级。 - 首屏瀑布图:Chrome DevTools 的 Network 面板,勾选「Disable cache」和网络限速(Slow 4G)。
看 RUM 的时候看 P75,不是平均值。平均值会被高端机拉好看。
核心指标的目标线:
| 指标 | 好 | 需要改进 |
|---|---|---|
| LCP(最大内容绘制) | ≤ 2.5s | > 4s |
| INP(交互到下次绘制) | ≤ 200ms | > 500ms |
| CLS(累积布局偏移) | ≤ 0.1 | > 0.25 |
二、按收益排序的动作
第一档:网络层(收益最大,改动最小)
- 静态资源上国内 CDN,并开启 Brotli 压缩。这一步通常比后面所有代码优化加起来收益都大。
- HTML 不要缓存,静态资源用内容哈希 + 长缓存(
Cache-Control: max-age=31536000, immutable)。 - 首屏关键资源加
<link rel="preload">,尤其是首屏图片和关键字体。 - 减少首屏请求的域名数量。每多一个域名就多一次 DNS + TCP + TLS,弱网下代价很大。
- 开 HTTP/2 或 HTTP/3。国内部分老旧代理对 HTTP/3 支持不好,要灰度验证。
第二档:字体(国内特有的大坑)
- 绝对不要用 Google Fonts。 国内访问
fonts.googleapis.com经常超时,会造成长时间白屏或字体闪烁。改成自托管。 - 中文字体必须子集化。 一个完整的中文字体动辄 5 到 10 MB。用
fonttools按实际用到的字符做子集,或者用unicode-range分片按需加载。标题用自定义字体、正文用系统字体,是最省的方案。 font-display: swap避免不可见文本。但 swap 会带来字体切换的抖动,正文量大时用optional更稳。- 系统字体栈在中文环境下已经够好看,能不自定义就不自定义:
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC",
"Hiragino Sans GB", "Microsoft YaHei", sans-serif;
第三档:图片
- 格式:WebP 兼容性已足够,AVIF 在国产浏览器上要做降级。用
<picture>给多格式。 - 尺寸:按设备宽度给
srcset,不要给手机推 2000px 宽的图。 - 首屏图片不要懒加载,反而会拖慢 LCP。首屏之外的才加
loading="lazy"。 - 必须写
width和height(或aspect-ratio),否则图片加载完会撑开布局,直接毁掉 CLS。 - LCP 元素通常就是首屏那张大图,给它加
fetchpriority="high"。
第四档:JavaScript
- 首屏 JS 体积是 LCP 和 INP 的主要杀手。 目标是首屏 JS 压缩后 150KB 以内。
- 路由级代码分割,非首屏组件动态导入。
- 删掉没用的依赖。用 bundle 分析工具看体积构成,经常能发现一个 moment 或者整个 lodash 被全量引入。
- 第三方脚本延后。统计、客服、埋点这类用
defer或者在load之后再插入。第三方脚本是性能问题里最常见的隐形元凶,且不受你控制。 - 长任务拆分。INP 差通常是某个事件处理函数里做了几百毫秒的同步计算,拆成分片或挪进 Worker。
第五档:渲染策略
- 内容型页面优先 SSR 或静态预渲染。纯客户端渲染的首屏必然要等 JS 下载 + 解析 + 请求数据,在弱网下很难看。
- SSR 之后注意 hydration 成本,大页面的 hydration 本身就是长任务。考虑局部 hydration。
- 骨架屏改善的是体感,不改善指标,但值得做。
三、微信内置浏览器
国内绕不开的特殊环境:
- 内核版本落后于同期 Chrome,新 API 要做特性检测。
- 部分 CSS 和视频行为不一致,尤其是自动播放策略。
- 分享卡片需要按微信规则配置,且要在真机上验证(开发者工具经常和真机不一致)。
- 页面被微信预加载时,某些计时指标会失真,RUM 上报要注意识别。
规则:所有性能改动都要在真实微信里、用一台中低端安卓机验证一遍。iPhone 上快不代表用户那里快。
四、验收
改完之后必须给出前后对比,只说「优化了」不算数:
| 项 | 优化前 | 优化后 |
|---|---|---|
| LCP (P75, 真实用户) | ||
| INP (P75) | ||
| CLS (P75) | ||
| 首屏 JS 压缩体积 | ||
| 首屏请求数 | ||
| 弱网(Slow 4G)白屏时间 |
RUM 数据要等一到两天才有统计意义,别改完当天就宣布成功。
五、常见误区
- 只在 Wi-Fi 和高端机上测。 用户的 P75 是中端安卓 + 4G。
- 为了指标好看把首屏内容砍掉。 LCP 变好了,但用户看到的是空页面。
- 无脑上懒加载,把首屏图也懒了,LCP 反而变差。
- 迷信打包体积。 200KB 的 JS 如果不阻塞首屏,不如 50KB 但同步执行的糟糕。
- 忽略第三方脚本。 自己的代码优化到极致,一个客服 SDK 拖后腿。
- 上了 CDN 就不管缓存策略,HTML 被缓存导致发版不生效,比慢更糟。