用户没有耐心等你慢慢加载:业界普遍建议首屏 LCP 在 2.5 秒内,每多一秒,流失和跳出都在增加。性能优化不是玄学,是有顺序、可验证的工程——按网络层 → 资源层 → 渲染层逐层排查,每一步都能用工具量化。
一、先定度量标准:Core Web Vitals
| 指标 | 衡量什么 | 建议阈值 |
|---|---|---|
| LCP | 最大内容(首屏主图/标题)加载时间 | ≤ 2.5s |
| INP(原 FID) | 页面交互响应延迟 | ≤ 200ms |
| CLS | 页面布局稳定性(跳动程度) | ≤ 0.1 |
这些指标来自 web.dev 的公开建议。先用 Lighthouse(Chrome DevTools 里直接跑)和 PageSpeed Insights(线上 URL 分析)拿一份基线报告,后面每改一步都重新跑,用分数说话。
二、网络层:把传输量压下去
- 开启压缩:Gzip 或更优的 Brotli(br),纯文本资源普遍能压掉 60%~80%;
- HTTP/2 / HTTP/3:多路复用解决连接数瓶颈,配合 HTTPS 在 Nginx/CDN 层开启;
- CDN 加速:静态资源分发到离用户近的节点,同时提供缓存与带宽能力;
- 合理缓存:强缓存 + 协商缓存配好(见HTTP 缓存一篇讲透),重复访问不重复下载。
三、资源层:图片和字体最容易被忽略
图片通常是首屏流量的最大头,按优先级处理:
- 格式换代:WebP / AVIF 比 JPEG/PNG 小得多,浏览器支持普遍,图片服务或构建工具可自动转换;
- 响应式 srcset:不同屏幕给不同尺寸,别让手机去下载 2K 大图;
- 懒加载:首屏以下的图片加
loading="lazy",滚动到才加载; - 显式宽高:给 img 设宽高或 aspect-ratio,防止加载完成后页面跳动(这正是 CLS 的主要来源);
- 首屏关键图可用
fetchpriority="high"提示浏览器优先加载。
字体:用 font-display: swap 避免文本不可见(FOIT);做子集化只加载用到的字形;中文站点尤其注意,全量中文字体很大,能少则少。
四、渲染层:让浏览器少干活
- 代码拆包(Code Splitting):路由级懒加载——访问首页只下载首页的 JS,其余页面按需加载;
- Tree Shaking:打包时去掉没引用的代码;Vite/webpack 都支持,留意别因副作用标记问题让摇树失效;
- 依赖与业务分离:把体积大且不变的第三方库(如框架、图表库)打成独立 chunk,配合长缓存,升级业务代码时不重新下载依赖;
- 关键 CSS 内联:首屏所需的少量 CSS 直接内联进 HTML,避免“CSS 阻塞首屏”的白屏等待;
- JS defer:脚本尽量
defer不阻塞解析,或用type="module"天然异步。
优化要盯首屏实际下载体积,而不是“项目总共多大”。用 DevTools 的 Network 面板看首屏传输量(Transfer)和瀑布图:哪条请求最慢、最大,就从哪下手。盲目拆包反而可能因请求过多拖慢首屏。
五、资源预加载三件套:preload / preconnect / prefetch
<!-- 提前连第三方源,省 DNS+TCP 握手(如字体、CDN) -->
<link rel="preconnect" href="https://fonts.example.com" crossorigin>
<!-- 首屏关键资源提前下载(如首屏大图/字体文件) -->
<link rel="preload" as="image" href="/img/hero.webp">
<!-- 空闲时预取下一个页面的资源 -->
<link rel="prefetch" href="/next-page.js">
- preload 只给真正关键的东西用,用多了反而挤占首屏带宽;
- preconnect 适合确定要访问的跨域源;
- prefetch 适合有把握的“下一步”,如首页对文章页的预取。
六、落地检查清单与工具
- 生产环境跑一遍 Lighthouse,记录 Performance 分数与 LCP/INP/CLS 三项数值;
- 按上面三层逐项整改,一次改一项、每项重新测,别一把梭导致不知道是谁的功劳;
- 用
web-vitals库把真实用户数据(RUM)上报,看全国各地的真实网络表现; - 持续监控:CI 里加性能门槛,或定期用 PageSpeed Insights 盯线上。
性能优化没有终点,但有一条主线:先减体积、再减请求、再调顺序、最后上 CDN 与缓存。按这个顺序做,方向永远正确。
从度量到落地,性能优化的每一步都是数据驱动的。把这条清单跑完一遍,你的站点在弱网环境下也能体面地打开。