前端性能优化实战:Core Web Vitals 从不及格到满分

Frontend Performance Optimization: From Failing to Perfect Core Web Vitals

| Sophia Li | 2026-07-27T20:52:15

公司官网的 Core Web Vitals 评分惨不忍睹,经过两周优化终于全绿了。这篇文章把具体做了哪些优化一一记录。

A detailed record of optimizations that improved a company website's Core Web Vitals from failing to perfect scores in two weeks.

## 惨淡的起点 用 PageSpeed Insights 跑了一下公司官网,移动端得分 38 分。LCP 4.8 秒,CLS 0.45,FID 380ms。三个指标全红,简直没眼看。 老板说影响 SEO 排名,限我两周搞定。 ## LCP 优化:4.8s → 1.2s LCP(Largest Contentful Paint)最大的内容通常是首屏的 banner 图片。 **做了什么:** 1. **图片格式换成 WebP/AVIF** ```html ``` 一张 800KB 的 JPG 变成了 180KB 的 AVIF,加载时间直接砍了 70%。 2. **预加载关键资源** ```html ``` 3. **服务端渲染首屏内容** 之前首屏是客户端渲染的,浏览器要下载 JS → 解析 → 执行 → 发 API 请求 → 渲染。改成 SSR 后,HTML 里直接有首屏内容,不用等 JS。 4. **CDN 配置优化** 开了 Brotli 压缩,HTML 从 120KB 压到 28KB。配了合理的 Cache-Control,静态资源设了一年缓存。 ## CLS 优化:0.45 → 0.02 CLS(Cumulative Layout Shift)就是页面元素乱跳。我们的问题主要是: 1. **图片没有设置尺寸** ```html ``` 2. **Web Font 闪烁** ```css /* 用 font-display: swap + size-adjust 减少字体切换时的布局偏移 */ @font-face { font-family: 'MainFont'; src: url('/fonts/main.woff2') format('woff2'); font-display: swap; size-adjust: 105%; /* 让后备字体和自定义字体大小接近 */ } ``` 3. **动态内容预留空间** 广告位、推荐区域这些异步加载的内容,用 `min-height` 预留空间。 ## INP 优化:380ms → 85ms FID 已经被 INP(Interaction to Next Paint)取代了。我们的问题是主线程被大量 JS 阻塞。 ```javascript // 之前:同步初始化所有模块 import { analytics, chat, recommendations, ads } from './modules'; analytics.init(); chat.init(); recommendations.init(); ads.init(); // 之后:非关键模块延迟加载 const analytics = () => import('./modules/analytics'); const chat = () => import('./modules/chat'); // 用 requestIdleCallback 在空闲时初始化 requestIdleCallback(() => { analytics().then(m => m.init()); chat().then(m => m.init()); }); ``` JS bundle 从 450KB 减到了首屏只需加载 120KB。 ## 最终结果 | 指标 | 优化前 | 优化后 | |------|--------|--------| | LCP | 4.8s | 1.2s | | CLS | 0.45 | 0.02 | | INP | 380ms | 85ms | | Lighthouse 分数 | 38 | 96 | 两周的优化工作,移动端从 38 分到 96 分。关键是这些优化都不复杂,但需要系统性地一个个排查和修复。分享给需要做类似优化的同学。


## Starting Point Company website scored 38 on PageSpeed Insights for mobile. LCP 4.8s, CLS 0.45, FID 380ms - all failing. ## Key Optimizations **LCP (4.8s → 1.2s):** Converted images to AVIF/WebP format, preloaded critical resources, implemented SSR for above-the-fold content, and enabled Brotli compression on CDN. **CLS (0.45 → 0.02):** Added explicit dimensions to images with aspect-ratio, used font-display: swap with size-adjust, and reserved space for dynamic content. **INP (380ms → 85ms):** Split JS bundles with dynamic imports, deferred non-critical module initialization to requestIdleCallback, reducing initial JS from 450KB to 120KB. ## Results Lighthouse score improved from 38 to 96 on mobile in two weeks. All Core Web Vitals now in the green zone.

← Back to News