主题
性能优化清单
目标
系统化优化网站性能指标,使 Core Web Vitals 全部达标(LCP<2.5s、FID<100ms、CLS<0.1),提升用户体验和SEO排名。
前置条件
- 网站已部署上线(Vercel、Cloudflare Pages 或其他平台)
- 可访问 Google Search Console 查看 Core Web Vitals 数据
- 有代码仓库的编辑权限
- 了解基本前端开发(HTML/CSS/JavaScript)
操作步骤
步骤1:测量当前性能基线
目的:建立量化基准,明确优化目标,避免盲目优化。 操作:
- 打开 PageSpeed Insights,输入你的网站URL。
- 分别测试 Mobile 和 Desktop 两个模式,记录以下指标:
- LCP(Largest Contentful Paint):最大内容渲染时间
- FID(First Input Delay):首次输入延迟
- CLS(Cumulative Layout Shift):累积布局偏移
- FCP(First Contentful Paint):首次内容绘制
- TTFB(Time to First Byte):首字节时间
- Speed Index:速度指数
- 打开 Google Search Console → 体验 → 核心网页指标,查看真实用户数据。
- 将所有指标填入性能追踪表格,标注不达标项:
指标 达标值 当前值 是否达标 LCP <2.5s - - INP <200ms - - CLS <0.1 - - - 使用 Chrome DevTools → Lighthouse → 生成本地报告,作为对比参考。 验证:
- 性能基线数据完整记录
- 明确了哪些指标不达标
- 有了量化对比基准
步骤2:优化Core Web Vitals
目的:直接针对Google排名核心指标进行优化,确保搜索排名不受性能拖累。 操作:
LCP优化(目标 < 2.5s):
- 识别LCP元素:在 DevTools → Performance 中录制页面加载,找到LCP元素(通常是首屏大图或标题文本)。
- 如果LCP元素是图片:
- 添加
fetchpriority="high"属性。 - 确保图片使用现代格式(WebP/AVIF),参考步骤3。
- 使用
<link rel="preload">预加载图片。
- 添加
- 如果LCP元素是文本:
- 确保字体已优化(参考步骤6)。
- 检查是否有CSS阻塞渲染,内联关键CSS。
- 减少服务器响应时间:
- 使用 Cloudflare CDN 缓存。
- 开启 Vercel Edge Functions 或 Static Generation。
- TTFB 控制在 800ms 以内。
INP优化(目标 < 200ms):
- 使用 PageSpeed Insights 的 INP 调试信息,找出慢交互。
- 拆分长任务(>50ms 的任务):
- 使用
requestIdleCallback延迟非关键逻辑。 - 将大任务拆分为多个小任务,用
setTimeout(fn, 0)让出主线程。
- 使用
- 减少事件回调中的DOM操作,使用
requestAnimationFrame批量更新。
CLS优化(目标 < 0.1):
- 为所有图片和视频设置明确的
width和height属性(或aspect-ratioCSS属性)。 - 为动态插入的内容预留空间(如广告位、推荐区域)。
- 避免在视口上方动态注入内容。
- 确保字体加载时使用
font-display: swap或optional。 - 使用 CSS
contain属性限制布局影响范围。
验证:
- PageSpeed Insights 中 LCP、INP、CLS 均达标
- Google Search Console 核心网页指标报告显示改善
步骤3:优化图片
目的:图片通常占页面总重量的50%以上,优化图片是提升加载速度最直接的手段。 操作:
- 格式转换:
- 使用 WebP 格式(兼容性 >97%)。
- 对支持 AVIF 的浏览器优先提供 AVIF(压缩率比WebP再高20-30%)。
- 使用
<picture>标签实现格式回退:html<picture> <source srcset="image.avif" type="image/avif"> <source srcset="image.webp" type="image/webp"> <img src="image.jpg" alt="描述" width="800" height="600"> </picture>
- 响应式图片:
- 使用
srcset和sizes提供不同分辨率版本:html<img srcset="img-480w.webp 480w, img-800w.webp 800w, img-1200w.webp 1200w" sizes="(max-width: 600px) 480px, 800px" src="img-800w.webp" alt="描述">
- 使用
- 懒加载:
- 为非首屏图片添加
loading="lazy"。 - 首屏图片不要懒加载,应使用
loading="eager"+fetchpriority="high"。
- 为非首屏图片添加
- 压缩:
- 使用工具批量压缩:Squoosh(手动)、Sharp(Node.js脚本)、或构建工具插件。
- 质量设置:WebP 质量 75-85 通常视觉无损。
- CDN图片优化(如使用 Cloudflare):
- 开启 Cloudflare Polish(自动压缩和WebP转换)。
- 开启 Cloudflare Mirage(自动响应式图片适配)。 验证:
- Lighthouse 图片审计无红色警告
- 图片总传输量减少 >40%
- 首屏图片在 LCP 前完成加载
步骤4:优化JavaScript代码
目的:减少JavaScript体积和执行时间,消除渲染阻塞资源。 操作:
- 代码分割(Code Splitting):
- 使用动态
import()按路由或功能拆分代码:javascript// 路由级别分割 const AboutPage = React.lazy(() => import('./AboutPage')); // 功能级别分割 const loadChart = () => import('chart.js'); - Next.js 用户:使用
dynamic()组件自动代码分割。
- 使用动态
- Tree Shaking:
- 确保构建工具(Webpack/Vite/Rollup)开启 Tree Shaking(生产模式默认开启)。
- 使用具名导入替代全量导入:javascript
// 错误:导入整个库 import _ from 'lodash'; // 正确:只导入需要的函数 import debounce from 'lodash/debounce';
- 移除未使用的代码:
- 检查 bundle 分析报告(
webpack-bundle-analyzer或@next/bundle-analyzer)。 - 移除未使用的依赖包。
- 用更轻量的替代库(如用
date-fns替代moment.js)。
- 检查 bundle 分析报告(
- 延迟非关键脚本:
- 第三方分析脚本添加
async或defer。 - 非关键功能使用动态
import()延迟到空闲时加载。
- 第三方分析脚本添加
- 避免客户端重型计算:
- 将数据处理、Markdown渲染等移到构建时(SSG)或服务端(SSR)。 验证:
- 主 JavaScript bundle < 200KB(gzip后)
- Lighthouse "Reduce JavaScript execution time" 无红色警告
- 首屏不需要的代码全部延迟加载
步骤5:配置缓存策略
目的:通过多层缓存减少重复请求,实现秒开体验。 操作:
- 浏览器缓存:
- 静态资源(JS/CSS/图片/字体)设置长期缓存:
Cache-Control: public, max-age=31536000, immutable - HTML页面设置短期缓存或不缓存:
Cache-Control: public, max-age=0, must-revalidate - 使用内容哈希文件名实现长期缓存(如
app-3f2a1b.js)。
- 静态资源(JS/CSS/图片/字体)设置长期缓存:
- CDN缓存(Cloudflare):
- 参考 Cloudflare全套配置 中的缓存规则设置。
- 静态资源 Edge Cache TTL 设为 1 month。
- HTML 页面 Edge Cache TTL 设为 4 hours。
- SWR(Stale-While-Revalidate)策略:
- 数据请求使用 SWR 模式:先返回缓存数据,同时后台更新。
- Next.js 用户可直接使用
next revalidate或@tanstack/query。 - 自定义实现:javascript
// 缓存优先,后台更新 async function fetchWithSWR(url) { const cached = localStorage.getItem(`swr:${url}`); if (cached) { fetch(url).then(data => localStorage.setItem(`swr:${url}`, JSON.stringify(data))); return JSON.parse(cached); } const data = await fetch(url); localStorage.setItem(`swr:${url}`, JSON.stringify(data)); return data; }
- Service Worker缓存(可选,PWA场景):
- 使用 Workbox 库配置缓存策略。
- App Shell 模式:缓存应用框架,动态加载内容。 验证:
- 二次访问页面加载时间 < 1s
- DevTools Network 中静态资源状态码为 304 或从缓存加载
- CDN 命中率 > 80%
步骤6:优化字体加载
目的:字体加载不当会导致文字闪烁(FOIT/FOUT)和布局偏移(CLS)。 操作:
- 使用
font-display:- 在
@font-face中添加font-display: swap(推荐)或font-display: optional。 swap:优先显示备用字体,加载完成后切换。optional:浏览器根据网络情况决定是否下载字体。
- 在
- 预加载关键字体:html
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin> - 子集化字体:
- 只包含网站实际使用的字符,大幅减小字体文件体积。
- 出海英文站:使用
latin子集即可。 - 使用
glyphhanger或fonttools进行子集化。
- 减少字体变体数量:
- 只加载实际使用的字重(Regular 400 + Bold 700 通常足够)。
- 避免加载 100-900 全部字重。
- 考虑系统字体栈:
- 对于非品牌字体(正文内容),使用系统字体栈可完全避免字体加载:css
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
- 对于非品牌字体(正文内容),使用系统字体栈可完全避免字体加载:
验证:
- Lighthouse "Ensure text remains visible during webfont load" 通过
- CLS 不因字体加载而偏移
- 字体文件总大小 < 100KB
步骤7:优化第三方脚本
目的:第三方脚本(分析、客服、广告)是性能杀手,需要严格控制。 操作:
- 审计第三方脚本:
- 在 DevTools → Network 中筛选第三方域名请求。
- 列出所有第三方脚本及其用途。
- 延迟加载非关键脚本:
- 分析脚本(Google Analytics、Mixpanel)→ 使用
async加载,或延迟到用户交互后加载。 - 客服组件(Intercom、Crisp)→ 延迟5秒或用户滚动后加载。
- 社交分享按钮 → 延迟到视口内时加载。
- 分析脚本(Google Analytics、Mixpanel)→ 使用
- 使用 facade 模式:
- 对于视频嵌入(YouTube)、地图(Google Maps),先显示静态占位图,用户点击后才加载实际组件。
- 替代重型方案:
- Google Analytics → 考虑 Vercel Analytics 或 Plausible(脚本 < 1KB)。
- Intercom → 考虑轻量级聊天方案如 Crisp 或 Tawk.to。
- 设置 Resource Hints:
- 对必须使用的第三方域名添加
preconnect:html<link rel="preconnect" href="https://www.googletagmanager.com">
- 对必须使用的第三方域名添加
验证:
- 第三方脚本总执行时间 < 200ms
- 主线程阻塞时间 < 150ms
- 不必要的第三方脚本已移除或延迟
检查清单
- [ ] 性能基线已测量并记录
- [ ] LCP < 2.5s
- [ ] INP < 200ms
- [ ] CLS < 0.1
- [ ] 所有图片使用 WebP/AVIF 格式
- [ ] 非首屏图片使用懒加载
- [ ] JavaScript 已代码分割,主 bundle < 200KB
- [ ] 浏览器缓存和CDN缓存已配置
- [ ] 字体使用 font-display: swap
- [ ] 第三方脚本已延迟或替换
- [ ] PageSpeed Insights 移动端评分 > 90
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| LCP 始终 > 2.5s | 服务器响应慢或LCP元素加载延迟 | 检查TTFB,优化服务端渲染;preload LCP图片;内联关键CSS |
| CLS 值偏高 | 图片无尺寸、字体闪烁、动态内容 | 给图片设width/height;font-display: swap;预留动态内容空间 |
| JS执行时间过长 | Bundle过大或未做代码分割 | 检查bundle分析报告;拆分路由级代码;Tree Shaking |
| 字体闪烁明显 | 字体文件大且无预加载 | preload关键字体;子集化;减少字重变体 |
| 第三方脚本拖慢速度 | 同步加载、执行时间长 | 全部改为async/defer;延迟到交互后加载;考虑轻量替代 |
| 缓存命中率低 | 缓存头设置不当 | 检查Cache-Control头;静态资源加内容哈希;配置CDN规则 |
| 移动端评分远低于桌面端 | 移动端CPU/网络受限 | 优先针对移动端优化;减少JS执行;更激进的代码分割 |
参考文章
- Cloudflare全套配置:CDN缓存和加速配置
- Vercel:自带性能分析和Edge优化
- Cloudflare:CDN缓存、Polish图片优化、Mirage响应式图片
- API调试指南:接口性能排查