Next.js Core Web Vitals 优化实战:LCP/FCP/CLS 全攻略
上个月我接手了一个电商项目的性能优化任务,Lighthouse 分数一直徘徊在 65 分左右,最让人头疼的是 LCP(最大内容绘制)一直在 3.5 秒上下浮动。老板说用户流失率很高,转化率也一直上不去。说实话,当时压力很大。
后来我花了两周时间系统地优化了 Core Web Vitals,最终把 Lighthouse 分数提升到 95 分,LCP 降到了 1.2 秒。更重要的是,转化率提升了 28%。这个结果让我意识到,性能优化不仅仅是技术指标,更是实实在在的业务价值。
根据 2025 年最新数据,只有 47% 的网站达到了 Google 的 Core Web Vitals 标准。性能差会导致 8-35% 的收入、排名和转化率损失。这不是危言耸听,而是真实的商业代价。
在这篇文章里,我会分享我在 Next.js 性能优化过程中积累的实战经验。你会学到:
- 3 个核心指标(LCP、INP、CLS)的具体优化方法
- 10+ 个可以直接复制的代码示例
- 5 个最容易踩的性能陷阱
Core Web Vitals 2025 年最新变化
在开始优化之前,我们得先搞清楚现在的游戏规则。很多文章还在讲 FID(首次输入延迟),但其实这个指标在 2024 年 3 月就被淘汰了。
当前的三大核心指标
Google 现在重点关注这三个指标:
-
LCP (Largest Contentful Paint) - 最大内容绘制
- 目标: ≤ 2.5 秒
- 衡量加载性能
- 在 Lighthouse 评分中占 25%
-
INP (Interaction to Next Paint) - 交互到下一次绘制
- 目标: ≤ 200ms
- 衡量交互响应速度
- 这是 2024 年 3 月替代 FID 的新指标
-
CLS (Cumulative Layout Shift) - 累积布局偏移
- 目标: < 0.1
- 衡量视觉稳定性
FCP(首次内容绘制)不再是核心指标,但它仍然重要,因为它影响用户的第一印象。
为什么要关注这些指标?
不知道你有没有遇到过这种情况:打开一个网站,正准备点击某个按钮,突然页面跳了一下,结果点到了别的地方。这就是 CLS 差的表现。
或者你访问一个网站,盯着白屏看了好几秒,心里想”是不是网络断了?”这就是 LCP 太慢。
根据 Chrome 团队的数据,顶级网站的 LCP 平均值约为 1,220ms。如果你的网站 LCP 超过 2.5 秒,你就落后了大部分竞争对手。
LCP 优化 - 让最大内容元素快速呈现
LCP 是我优化时花时间最多的指标,也是效果最明显的。接下来我会一步步告诉你怎么优化。
第一步:找出你的 LCP 元素
优化之前,你得先知道哪个元素是 LCP。通常情况下,LCP 元素是:
- 首屏的 hero 图片
- 视频的封面图
- 大段的标题或文本区块
快速查看方法:
- 打开 Chrome DevTools(F12)
- 按
Ctrl+Shift+P(Mac 用Cmd+Shift+P) - 输入 “Show Rendering”
- 勾选 “Core Web Vitals”
- 刷新页面,右上角会显示 LCP 元素
我当时发现,那个电商项目的 LCP 元素是首页的主视觉图片,一张 2MB 的 JPG。问题就出在这里。
图片优化:next/image 的正确打开方式
很多人以为用了 Next.js 的 Image 组件就万事大吉了,其实不然。我一开始也是这么想的,结果 LCP 还是很慢。
优先级设置才是关键
对于 LCP 图片,你必须明确告诉浏览器”这张图很重要,优先加载!”。Next.js 提供了两种方式:
Next.js 13-15(主流版本):
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero-image.jpg"
width={1200}
height={630}
priority // 关键!告诉浏览器优先加载
fetchPriority="high" // 双保险
alt="产品主视觉"
/>
);
}
Next.js 16+(最新版本):
Next.js 16 废弃了 priority 属性,改用这种写法:
<Image
src="/hero-image.jpg"
width={1200}
height={630}
loading="eager" // 立即加载,不使用懒加载
fetchPriority="high" // 高优先级
alt="产品主视觉"
/>
你可能会想,为什么要设置两个属性?因为 priority 会自动添加预加载标签,而 fetchPriority 告诉浏览器资源的重要程度。两者配合效果最好。
对比一下错误的写法:
// ❌ 错误:会被懒加载,LCP 很慢
<Image
src="/hero-image.jpg"
width={1200}
height={630}
alt="产品主视觉"
/>
// ❌ 错误:缺少尺寸信息
<Image
src="/hero-image.jpg"
priority
alt="产品主视觉"
/>
尺寸声明的重要性
Next.js 的 Image 组件要求你指定 width 和 height,这不是故意刁难你,而是为了避免 CLS(布局偏移)。
如果你用响应式布局,可以这样写:
// 使用 fill 属性实现响应式
<div style={{ position: 'relative', width: '100%', aspectRatio: '16/9' }}>
<Image
src="/hero-image.jpg"
fill
priority
style={{ objectFit: 'cover' }}
alt="产品主视觉"
/>
</div>
注意父容器必须有明确的尺寸或 aspect-ratio,否则图片不知道该渲染多大。
字体优化:next/font 自动内联
字体加载慢也会拖累 LCP,尤其是中文字体动辄几 MB。Next.js 13 引入了 next/font,可以自动优化字体加载。
使用 Google Fonts:
// app/layout.jsx
import { Inter, Noto_Sans_SC } from 'next/font/google';
const inter = Inter({
subsets: ['latin'],
display: 'swap', // 避免字体闪烁
});
const notoSansSC = Noto_Sans_SC({
subsets: ['chinese-simplified'],
weight: ['400', '700'],
display: 'swap',
});
export default function RootLayout({ children }) {
return (
<html lang="zh-CN" className={`${inter.className} ${notoSansSC.className}`}>
<body>{children}</body>
</html>
);
}
使用自定义字体:
import localFont from 'next/font/local';
const myFont = localFont({
src: './my-font.woff2',
display: 'swap',
});
export default function Layout({ children }) {
return <div className={myFont.className}>{children}</div>;
}
next/font 会自动做这些优化:
- 自动内联字体 CSS,减少网络请求
- 自动子集化,只加载需要的字符
- 自动预加载字体文件
- 消除布局偏移
我把项目的字体切换到 next/font 后,LCP 又降了 0.3 秒。
减少服务器响应时间
图片优化完了,字体也优化了,但 LCP 还是慢怎么办?可能是服务器响应时间(TTFB)的问题。
静态生成优先
Next.js 提供了多种渲染方式,性能从好到差排序是:
- SSG (Static Site Generation) - 构建时生成 HTML,最快
- ISR (Incremental Static Regeneration) - 按需重新生成静态页面
- SSR (Server-Side Rendering) - 每次请求都生成 HTML,较慢
- CSR (Client-Side Rendering) - 客户端渲染,LCP 最慢
能用 SSG 就用 SSG:
// app/blog/[slug]/page.jsx
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map((post) => ({
slug: post.slug,
}));
}
export default async function BlogPost({ params }) {
const post = await getPost(params.slug);
return <article>{/* ... */}</article>;
}
如果数据需要实时更新,用 ISR:
// app/products/[id]/page.jsx
export const revalidate = 3600; // 每小时重新生成一次
export default async function ProductPage({ params }) {
const product = await getProduct(params.id);
return <div>{/* ... */}</div>;
}
使用 CDN 和 Edge Network
如果你部署在 Vercel 上,它会自动把静态资源分发到全球的 Edge Network,大幅降低 TTFB。
如果你用其他平台,可以配合 Cloudflare、AWS CloudFront 等 CDN 使用。
避免在服务端做复杂计算
这个坑我也踩过。有一次我在服务端做了一个复杂的数据处理,每次渲染都要花 500ms,直接拖累了 LCP。
反面教材:
// ❌ 错误:每次请求都要计算
export default async function Page() {
const data = await fetchData();
const processed = heavyProcessing(data); // 耗时 500ms
return <div>{processed}</div>;
}
正确做法:
把计算结果缓存起来,或者在构建时计算好:
// ✅ 正确:构建时计算
export async function generateStaticParams() {
const data = await fetchData();
const processed = heavyProcessing(data);
// 把结果存到数据库或文件
await saveProcessedData(processed);
}
export default async function Page() {
const processed = await getProcessedData(); // 直接读取
return <div>{processed}</div>;
}
CLS 优化 - 消除布局抖动
CLS(累积布局偏移)是最让人头疼的指标。页面突然跳一下,用户体验很差。老实讲,这个问题困扰了我好一阵子。
图片和媒体元素的尺寸预留
CLS 最常见的原因就是图片加载后改变了布局。解决办法很简单:提前告诉浏览器图片的尺寸。
Next.js Image 组件会自动处理:
// ✅ 正确:指定宽高,不会产生 CLS
<Image
src="/product.jpg"
width={400}
height={300}
alt="产品图"
/>
如果是动态加载的图片呢?
假设你从 CMS 获取图片,不知道尺寸:
// ✅ 正确:使用 aspect-ratio 预留空间
<div style={{ position: 'relative', width: '100%', aspectRatio: '4/3' }}>
<Image
src={dynamicImageUrl}
fill
style={{ objectFit: 'cover' }}
alt="动态图片"
/>
</div>
视频也一样:
<video
width="1280"
height="720"
poster="/video-poster.jpg"
controls
>
<source src="/video.mp4" type="video/mp4" />
</video>
动态内容的空间预留
广告、通知条、嵌入内容(如 Twitter 卡片)都会导致 CLS。你得提前为它们预留空间。
广告容器:
// ✅ 正确:预留广告高度
<div
style={{
minHeight: '250px', // Google AdSense 标准广告高度
backgroundColor: '#f0f0f0' // 占位背景色
}}
>
{/* 广告脚本 */}
<ins className="adsbygoogle" />
</div>
通知条:
如果你的网站有顶部通知条,别让它突然出现:
// ❌ 错误:突然出现,导致页面下移
{showBanner && <NotificationBanner />}
// ✅ 正确:提前预留空间
<div style={{ minHeight: '60px' }}>
{showBanner ? <NotificationBanner /> : <div style={{ height: '60px' }} />}
</div>
骨架屏(Skeleton):
对于动态加载的内容,用骨架屏占位:
function ProductList() {
const { data, isLoading } = useQuery('products', fetchProducts);
if (isLoading) {
return (
<div className="grid grid-cols-3 gap-4">
{Array.from({ length: 6 }).map((_, i) => (
<div key={i} className="skeleton" style={{ height: '300px' }} />
))}
</div>
);
}
return (
<div className="grid grid-cols-3 gap-4">
{data.map(product => <ProductCard key={product.id} {...product} />)}
</div>
);
}
字体加载优化
字体加载也会导致 CLS,表现为”文字闪烁”或”字体跳变”。
next/font 会自动处理这个问题,但你也可以手动优化:
const inter = Inter({
subsets: ['latin'],
display: 'optional', // 如果字体没加载完,直接用系统字体,不等待
adjustFontFallback: true, // 自动调整备用字体的大小,减少跳变
});
display 属性的几种选择:
swap: 先显示备用字体,加载完成后切换(可能导致 CLS)optional: 如果字体没及时加载完,直接用备用字体(推荐)block: 短暂隐藏文字,等字体加载完成(不推荐)fallback: 介于 swap 和 optional 之间
我推荐用 optional,虽然可能看不到自定义字体,但用户体验更好。
避免 JavaScript 驱动的响应式布局
这是 2025 年最常见的 CLS 陷阱! 我看到很多 Next.js 项目都在犯这个错误。
典型的错误代码:
// ❌ 错误:会导致严重的 CLS
import { useMediaQuery } from '@/hooks/useMediaQuery';
export default function ResponsiveLayout() {
const isMobile = useMediaQuery('(max-width: 768px)');
return (
<div>
{isMobile ? (
<MobileNav />
) : (
<DesktopNav />
)}
</div>
);
}
为什么会有 CLS?因为:
- 页面首次渲染时,JavaScript 还没执行,
isMobile是undefined或默认值 - JavaScript 执行后,
useMediaQuery返回真实值 - 组件重新渲染,布局突变
这个问题在服务端渲染(SSR)时更严重,因为服务端不知道客户端的屏幕宽度。
正确的做法:用 CSS 媒体查询
// ✅ 正确:用 CSS 控制显示/隐藏,不会产生 CLS
export default function ResponsiveLayout() {
return (
<>
<nav className="mobile-nav md:hidden">
<MobileNav />
</nav>
<nav className="desktop-nav hidden md:block">
<DesktopNav />
</nav>
</>
);
}
或者用 CSS-in-JS:
export default function ResponsiveLayout() {
return (
<div className="responsive-container">
<MobileNav />
<DesktopNav />
<style jsx>{`
.responsive-container > :global(.mobile-nav) {
display: block;
}
.responsive-container > :global(.desktop-nav) {
display: none;
}
@media (min-width: 768px) {
.responsive-container > :global(.mobile-nav) {
display: none;
}
.responsive-container > :global(.desktop-nav) {
display: block;
}
}
`}</style>
</div>
);
}
如果你确实需要 JavaScript 判断(比如需要根据设备做不同的数据请求),可以在服务端获取 User-Agent:
// app/page.jsx
import { headers } from 'next/headers';
export default async function Page() {
const headersList = headers();
const userAgent = headersList.get('user-agent') || '';
const isMobile = /mobile/i.test(userAgent);
return (
<div>
{isMobile ? <MobileView /> : <DesktopView />}
</div>
);
}
这样服务端和客户端渲染的结果一致,不会产生 CLS。
FCP 优化 - 加速首次内容绘制
FCP(首次内容绘制)虽然不是核心指标,但它影响用户的第一印象。如果用户看到白屏时间太长,可能直接关闭页面。
关键资源优化
FCP 慢通常是因为有阻塞渲染的资源。打开 Chrome DevTools 的 Coverage 面板,看看哪些 CSS 和 JavaScript 没用到。
内联关键 CSS:
Next.js 会自动处理 CSS 优化,但你也可以手动内联关键样式:
// app/layout.jsx
export default function RootLayout({ children }) {
return (
<html>
<head>
<style
dangerouslySetInnerHTML={{
__html: `
/* 关键 CSS:首屏必需的样式 */
body { margin: 0; font-family: system-ui; }
.hero { height: 100vh; }
`,
}}
/>
</head>
<body>{children}</body>
</html>
);
}
延迟非关键 CSS:
对于首屏不需要的样式(如弹窗、折叠区域),可以延迟加载:
// 在组件中动态导入 CSS
import dynamic from 'next/dynamic';
const Modal = dynamic(() => import('./Modal'), {
loading: () => <p>Loading...</p>,
});
第三方脚本管理
第三方脚本(如 Google Analytics、广告、社交媒体插件)是性能杀手。很多网站的 FCP 慢就是因为这个。
使用 next/script:
Next.js 提供了 Script 组件,可以控制脚本的加载时机:
import Script from 'next/script';
export default function Layout({ children }) {
return (
<>
{children}
{/* Google Analytics:页面可交互后再加载 */}
<Script
src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"
strategy="lazyOnload"
/>
<Script id="ga-init" strategy="lazyOnload">
{`
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
`}
</Script>
{/* Facebook Pixel:延迟加载 */}
<Script
src="https://connect.facebook.net/en_US/fbevents.js"
strategy="lazyOnload"
/>
</>
);
}
strategy 属性说明:
beforeInteractive: 页面可交互前加载(用于关键脚本)afterInteractive: 页面可交互后加载(默认值)lazyOnload: 空闲时加载(推荐用于分析和广告)worker: 在 Web Worker 中运行(实验性功能)
我把所有非必需的第三方脚本改成 lazyOnload 后,FCP 提升了 0.8 秒。
代码分割和懒加载
Next.js 自动做代码分割,但有时候你需要手动优化。
懒加载组件:
对于首屏不需要的组件,可以动态导入:
import dynamic from 'next/dynamic';
// 懒加载评论组件
const Comments = dynamic(() => import('./Comments'), {
loading: () => <div>加载评论中...</div>,
ssr: false, // 不做服务端渲染
});
export default function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
{/* 滚动到这里才加载评论 */}
<Comments postId={post.id} />
</article>
);
}
懒加载第三方库:
有些库很大(如图表库、富文本编辑器),应该按需加载。
案例:延迟加载图表库节省 800KB
我之前遇到一个项目,每个页面都引入了 Chart.js,但只有仪表盘页面用到。结果每个页面都要加载 800KB 的代码。
优化前:
// ❌ 错误:全局导入,所有页面都加载
import { Chart } from 'chart.js';
export default function Dashboard() {
return <canvas ref={chartRef} />;
}
优化后:
// ✅ 正确:只在需要时加载
import dynamic from 'next/dynamic';
const ChartComponent = dynamic(() => import('./ChartComponent'), {
loading: () => <div>加载图表中...</div>,
ssr: false,
});
export default function Dashboard() {
return <ChartComponent />;
}
// ChartComponent.jsx
import { Chart } from 'chart.js';
export default function ChartComponent() {
return <canvas ref={chartRef} />;
}
这样,只有访问仪表盘的用户才会下载 Chart.js,其他页面不受影响。
懒加载图片:
除了 LCP 图片,其他图片应该懒加载:
<Image
src="/feature-image.jpg"
width={600}
height={400}
loading="lazy" // 默认值,可以省略
alt="功能介绍"
/>
监控与持续优化
优化完了不代表就结束了。性能是持续的过程,你需要定期检查和调整。
使用 Lighthouse CI 自动化测试
手动跑 Lighthouse 很费时间,而且容易忘记。更好的办法是集成到 CI/CD 流程。
安装 Lighthouse CI:
npm install -D @lhci/cli
配置文件 lighthouserc.js:
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000/', 'http://localhost:3000/products'],
numberOfRuns: 3, // 跑 3 次取平均值
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }], // Performance ≥ 90
'first-contentful-paint': ['error', { maxNumericValue: 2000 }], // FCP ≤ 2s
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }], // LCP ≤ 2.5s
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }], // CLS < 0.1
},
},
upload: {
target: 'temporary-public-storage',
},
},
};
GitHub Actions 配置:
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on: [push]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm install
- run: npm run build
- run: npm run start &
- run: npx @lhci/cli autorun
这样每次 push 代码,都会自动跑 Lighthouse 测试。如果性能退步了,CI 会失败,提醒你修复。
Real User Monitoring (RUM)
Lighthouse 测试的是实验室环境,真实用户的体验可能不一样。你需要收集真实用户的 Core Web Vitals 数据。
使用 Vercel Analytics:
如果你部署在 Vercel 上,可以一键开启 Analytics:
// app/layout.jsx
import { Analytics } from '@vercel/analytics/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
);
}
使用 web-vitals 库:
如果不用 Vercel,可以用 Google 的 web-vitals 库:
npm install web-vitals
// app/layout.jsx
'use client';
import { useEffect } from 'react';
import { onLCP, onFID, onCLS, onINP } from 'web-vitals';
function sendToAnalytics(metric) {
// 发送到你的分析服务
fetch('/api/analytics', {
method: 'POST',
body: JSON.stringify(metric),
});
}
export default function Analytics() {
useEffect(() => {
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
}, []);
return null;
}
Google Search Console:
Google Search Console 的”核心网页指标”报告会显示你网站在真实用户中的表现,还会标出需要改进的页面。
常见陷阱和解决方案
最后,我总结了 5 个最容易踩的坑:
陷阱 1: 过度使用客户端 JavaScript
很多开发者习惯用 React 做一切,结果整个页面都依赖 JavaScript。如果 JS 加载失败或太慢,用户看到的是白屏。
解决方案:
- 优先使用 Server Components(Next.js 13+ 默认)
- 只在必要时使用 ‘use client’
- 用 Progressive Enhancement 思想:先保证基本功能可用,再增强交互
陷阱 2: 忽略移动端性能
桌面端跑得快不代表移动端也快。移动设备 CPU 弱、网络慢,性能问题更明显。
解决方案:
- 用 Lighthouse 的”移动设备”模式测试
- 限制网络速度(Chrome DevTools → Network → Throttling)
- 限制 CPU(Chrome DevTools → Performance → CPU)
陷阱 3: 第三方脚本未做优化
Google Analytics、Facebook Pixel、Intercom、Hotjar…每个脚本都会拖累性能。
解决方案:
- 全部用
next/script包装,设置strategy="lazyOnload" - 定期审查:哪些脚本是必需的?能不能减少?
- 考虑用服务端跟踪代替客户端跟踪
陷阱 4: 图片格式选择不当
还在用 PNG 和 JPG?那你落伍了。WebP 和 AVIF 可以节省 30-50% 的体积。
解决方案:
Next.js Image 组件会自动转换格式,但你需要确保服务器支持:
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'], // 优先使用现代格式
},
};
陷阱 5: 忽视服务端性能
前端优化做得再好,如果服务端响应慢,一切白搭。
解决方案:
- 优化数据库查询(加索引、减少 N+1 查询)
- 使用缓存(Redis、CDN)
- 监控服务端性能(APM 工具如 New Relic、Datadog)
总结
回顾一下我们讲的内容:
LCP 优化关键点:
- 给 LCP 图片设置
priority和fetchPriority="high" - 使用
next/font优化字体加载 - 优先用 SSG 和 ISR,减少服务端计算
- 使用 CDN 降低 TTFB
CLS 优化关键点:
- 所有图片和媒体元素必须指定尺寸
- 为动态内容预留空间(广告、通知条)
- 避免用 JavaScript hooks 做响应式布局
- 使用
next/font减少字体跳变
FCP 优化关键点:
- 延迟加载非关键资源
- 第三方脚本用
next/script包装,设置lazyOnload - 懒加载大型库和非首屏组件
持续优化:
- 用 Lighthouse CI 自动化测试
- 收集真实用户数据(RUM)
- 定期审查和清理不必要的代码
性能优化是一个”测量 → 优化 → 再测量”的循环过程。不要指望一次性搞定,而是持续关注和改进。
当我看到 Lighthouse 分数终于突破 90 时,那种成就感真的很爽。更重要的是,转化率的提升证明了这些努力是值得的。
行动清单
现在轮到你了。我建议你按这个顺序开始:
-
立即行动:
- 用 Lighthouse 测试你的 Next.js 项目
- 找出 LCP 元素,看看有没有设置
priority - 检查是否有
useMediaQuery等导致 CLS 的代码
-
本周完成:
- 优化 LCP 图片(priority + fetchPriority)
- 把字体切换到
next/font - 给动态内容加上占位符
-
下周完成:
- 第三方脚本改用
lazyOnload - 懒加载大型库和非首屏组件
- 设置 Lighthouse CI 自动化测试
- 第三方脚本改用
-
持续做:
- 每月检查 Lighthouse 分数
- 关注 Google Search Console 的核心网页指标报告
- 及时修复性能退步的问题
记住:性能优化不是一次性任务,而是持续的过程。祝你优化顺利!
Next.js Core Web Vitals 优化完整流程
优化LCP、INP、CLS三大核心指标,提升Lighthouse分数到90+
⏱️ 预计耗时: 8 小时
- 1
步骤1: 优化LCP(最大内容绘制)
目标:≤2.5秒
优化方法:
• 使用next/image优化图片(自动WebP/AVIF转换)
• 首屏关键图片添加priority属性
• 预加载关键资源(使用<link rel="preload">)
• 优化服务器响应时间(使用CDN、Edge Functions)
• 减少阻塞渲染的资源(延迟加载非关键CSS/JS)
• 使用React Server Components减少客户端JS
检查工具:
• Lighthouse Performance报告
• Chrome DevTools Performance面板
• WebPageTest在线测试 - 2
步骤2: 优化INP(交互到下一次绘制)
目标:≤200ms
优化方法:
• 减少JavaScript执行时间(代码分割、懒加载)
• 使用React Server Components减少客户端JS
• 优化事件处理(防抖、节流、事件委托)
• 避免长任务阻塞主线程(使用Web Workers)
• 优化第三方脚本(延迟加载、使用async/defer)
• 使用Suspense和流式渲染
检查工具:
• Chrome DevTools Performance面板
• Web Vitals Chrome扩展
• Real User Monitoring (RUM)工具 - 3
步骤3: 优化CLS(累积布局偏移)
目标:≤0.1
优化方法:
• 设置图片和视频的宽高(或使用aspect-ratio)
• 避免动态插入内容(预留空间)
• 使用font-display: swap避免字体加载导致的偏移
• 预留广告位空间(避免广告加载后推挤内容)
• 使用CSS Grid/Flexbox而不是绝对定位
• 避免在现有内容上方插入新内容
检查工具:
• Lighthouse CLS报告
• Chrome DevTools Performance面板的Layout Shift记录
• WebPageTest可视化CLS - 4
步骤4: 使用Next.js性能优化特性
Next.js优化技巧:
• 使用Image组件自动优化图片
• 使用Font Optimization自动优化字体
• 使用React Server Components减少客户端JS
• 使用Streaming SSR提升首屏速度
• 使用Dynamic Imports代码分割
• 使用next/dynamic延迟加载组件
配置检查:
• next.config.js性能相关配置
• 检查bundle大小(npm run build) - 5
步骤5: 监控和持续优化
监控工具:
• Google Search Console Core Web Vitals报告
• Vercel Analytics(如果使用Vercel)
• Web Vitals Chrome扩展
• Real User Monitoring (RUM)工具
持续优化:
• 每月检查Lighthouse分数
• 关注Search Console的Core Web Vitals报告
• 及时修复性能退步的问题
• A/B测试优化效果
常见问题
Core Web Vitals 的三个指标是什么?
如何优化LCP?
INP 和 FID 有什么区别?
如何避免CLS(布局偏移)?
性能优化后多久能看到效果?
Next.js 的哪些特性有助于性能优化?
如何监控Core Web Vitals?
15 分钟阅读 · 发布于: 2025年12月19日 · 修改于: 2026年1月22日
相关文章
Next.js 电商实战:购物车与 Stripe 支付完整实现指南
Next.js 电商实战:购物车与 Stripe 支付完整实现指南
Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战
Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战
Next.js 单元测试实战:Jest + React Testing Library 完整配置指南

评论
使用 GitHub 账号登录后即可评论