Core Web Vitals 2026 新标准解读
2026 年的重大变化:INP 正式取代 FID
2024 年 3 月,Google 正式宣布 INP(Interaction to Next Paint) 取代 FID(First Input Delay)成为 Core Web Vitals 的核心指标。经过两年的过渡期,2026 年 INP 已完全成为搜索排名的重要因素。
为什么要替换 FID?
FID 的局限性:
| 问题 | 说明 |
|---|---|
| 只测量首次交互 | 忽略后续所有交互的延迟 |
| 只测量输入延迟 | 不包含事件处理和渲染时间 |
| 样本偏差 | 某些用户可能永远不触发交互 |
| 无法反映真实体验 | 首次交互可能很快,但后续很慢 |
INP 的优势:
FID 测量范围:
┌──────────────────────────────────────────────────┐
│ 用户点击 → 浏览器开始处理 │ FID 结束 │
│ ▼ ▼ │ │
│ [===========] │ │
│ 只测这一段 │ │
└──────────────────────────────────────────────────┘
INP 测量范围:
┌──────────────────────────────────────────────────┐
│ 用户点击 → 处理事件 → 渲染完成 │ INP 结束 │
│ ▼ ▼ ▼ │ │
│ [================================] │
│ 完整的交互响应时间 │
└──────────────────────────────────────────────────┘
2026 年 Core Web Vitals 完整指标体系
| 指标 | 全称 | 测量内容 | 良好阈值 | 需改进 | 差 |
|---|---|---|---|---|---|
| LCP | Largest Contentful Paint | 最大内容绘制时间 | ≤ 2.5s | ≤ 4s | > 4s |
| INP | Interaction to Next Paint | 交互到下一次绘制 | ≤ 200ms | ≤ 500ms | > 500ms |
| CLS | Cumulative Layout Shift | 累积布局偏移 | ≤ 0.1 | ≤ 0.25 | > 0.25 |
INP 深度解析
INP 的计算方式
INP 并非所有交互延迟的平均值,而是采用高百分位值策略:
// INP 计算逻辑(简化版)
function calculateINP(interactions) {
// 按延迟时间排序
const sorted = interactions.sort((a, b) => b.duration - a.duration);
// 根据交互数量选择百分位
// 交互少于 50 次:取最大值
// 交互 50 次以上:取第 98 百分位
const count = sorted.length;
if (count < 50) {
return sorted[0]?.duration ?? 0;
}
// 98th percentile
const index = Math.floor(count * 0.02);
return sorted[index].duration;
}
为什么选择高百分位而非平均值?
- 平均值会被大量快速交互"稀释"
- 用户对慢交互的感知更强烈
- 高百分位更能反映"最坏情况"体验
什么算作一次交互?
INP 追踪以下类型的交互:
// INP 追踪的交互类型
const trackedInteractions = {
// 点击相关
click: true,
dblclick: true,
contextmenu: true,
// 键盘相关
keydown: true,
keyup: true,
keypress: true,
// 触摸相关
touchstart: true,
touchend: true,
// 指针相关
pointerdown: true,
pointerup: true
};
// 以下不计入 INP
const notTracked = {
scroll: '滚动不是离散交互',
mousemove: '持续性事件',
hover: '非用户主动操作'
};
INP 的三个阶段
一次完整的交互由三个阶段组成:
┌─────────────────────────────────────────────────────────────┐
│ INP 总时长 │
├───────────────┬───────────────────────┬────────────────────┤
│ Input Delay │ Processing Time │ Presentation │
│ 输入延迟 │ 处理时间 │ 呈现延迟 │
├───────────────┼───────────────────────┼────────────────────┤
│ 主线程被占用 │ 事件处理函数执行 │ 样式计算+布局+绘制 │
│ 导致的等待 │ │ │
├───────────────┼───────────────────────┼────────────────────┤
│ 优化方向: │ 优化方向: │ 优化方向: │
│ - 减少长任务 │ - 优化事件处理逻辑 │ - 减少 DOM 操作 │
│ - 使用调度器 │ - 避免同步布局 │ - 使用 transform │
│ - Web Worker │ - 防抖/节流 │ - 避免 Layout │
└───────────────┴───────────────────────┴────────────────────┘
测量 Core Web Vitals
使用 web-vitals 库
import { onCLS, onINP, onLCP } from 'web-vitals';
// 基础用法
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
// 详细报告
function sendToAnalytics(metric) {
const body = {
name: metric.name,
value: metric.value,
rating: metric.rating, // 'good' | 'needs-improvement' | 'poor'
delta: metric.delta, // 与上次报告的差值
id: metric.id, // 唯一标识
navigationType: metric.navigationType,
entries: metric.entries // 相关 PerformanceEntry
};
// 发送到分析服务
navigator.sendBeacon('/analytics', JSON.stringify(body));
}
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);
在 Vue/Nuxt 中集成
// plugins/web-vitals.client.ts
import { onCLS, onINP, onLCP } from 'web-vitals';
export default defineNuxtPlugin(() => {
// 仅在客户端运行
if (process.server) return;
const sendMetric = (metric: Metric) => {
// 发送到你的分析服务
$fetch('/api/analytics/vitals', {
method: 'POST',
body: {
name: metric.name,
value: metric.value,
rating: metric.rating,
url: window.location.pathname,
timestamp: Date.now()
}
});
};
onLCP(sendMetric);
onINP(sendMetric);
onCLS(sendMetric);
});
在 Next.js 中集成
// app/components/WebVitals.tsx
'use client';
import { useEffect } from 'react';
import { onCLS, onINP, onLCP } from 'web-vitals';
export function WebVitals() {
useEffect(() => {
const sendMetric = (metric) => {
// 使用 Next.js 的 Analytics
window.gtag?.('event', metric.name, {
value: Math.round(metric.name === 'CLS' ? metric.value * 1000 : metric.value),
event_label: metric.id,
non_interaction: true,
});
};
onLCP(sendMetric);
onINP(sendMetric);
onCLS(sendMetric);
}, []);
return null;
}
// app/layout.tsx
import { WebVitals } from './components/WebVitals';
export default function RootLayout({ children }) {
return (
<html>
<body>
<WebVitals />
{children}
</body>
</html>
);
}
LCP 优化策略 2026
LCP 元素识别
LCP 候选元素类型:
<img>元素<svg>内的<image>元素<video>元素的封面图- 通过
background-image加载图片的元素 - 包含文本节点的块级元素
// 获取 LCP 元素信息
const observer = new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP 元素:', lastEntry.element);
console.log('LCP 时间:', lastEntry.startTime);
console.log('LCP 大小:', lastEntry.size);
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
2026 年 LCP 优化清单
## 资源发现优化
- [ ] 使用 `<link rel="preload">` 预加载 LCP 图片
- [ ] 避免懒加载首屏 LCP 元素
- [ ] 优化资源发现时间(fetchpriority="high")
## 资源加载优化
- [ ] 使用现代图片格式(AVIF > WebP > JPEG)
- [ ] 实施响应式图片(srcset + sizes)
- [ ] 启用 HTTP/2 或 HTTP/3
- [ ] 优化 CDN 配置
## 渲染优化
- [ ] 减少关键 CSS
- [ ] 避免渲染阻塞资源
- [ ] 优化 Web 字体加载
资源优先级提示
<!-- 2026 年推荐的资源优先级设置 -->
<!-- LCP 图片:最高优先级 -->
<img
src="/hero.webp"
fetchpriority="high"
decoding="async"
alt="Hero Image"
/>
<!-- 预加载关键资源 -->
<link rel="preload" href="/hero.webp" as="image" fetchpriority="high">
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/main-font.woff2" as="font" type="font/woff2" crossorigin>
<!-- 预连接到关键域名 -->
<link rel="preconnect" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://analytics.example.com">
<!-- 降低非关键资源优先级 -->
<img src="/below-fold.webp" fetchpriority="low" loading="lazy" />
INP 优化策略 2026
识别慢交互
// 使用 PerformanceObserver 监控慢交互
const slowInteractions = [];
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 200) { // INP 阈值
slowInteractions.push({
name: entry.name,
duration: entry.duration,
startTime: entry.startTime,
processingStart: entry.processingStart,
processingEnd: entry.processingEnd,
// 分解三个阶段
inputDelay: entry.processingStart - entry.startTime,
processingTime: entry.processingEnd - entry.processingStart,
presentationDelay: entry.duration - (entry.processingEnd - entry.startTime)
});
console.warn('慢交互检测:', slowInteractions[slowInteractions.length - 1]);
}
}
});
observer.observe({ type: 'event', buffered: true, durationThreshold: 16 });
优化输入延迟(Input Delay)
// ❌ 长任务阻塞主线程
function processLargeData(data) {
// 同步处理 100000 条数据
return data.map(item => heavyComputation(item));
}
// ✅ 使用 scheduler.yield() 拆分长任务
async function processLargeDataOptimized(data) {
const results = [];
const chunkSize = 1000;
for (let i = 0; i < data.length; i += chunkSize) {
const chunk = data.slice(i, i + chunkSize);
results.push(...chunk.map(item => heavyComputation(item)));
// 让出主线程,允许处理用户交互
if (i + chunkSize < data.length) {
await scheduler.yield();
}
}
return results;
}
// ✅ 使用 requestIdleCallback 处理非关键任务
function scheduleNonCriticalWork(callback) {
if ('requestIdleCallback' in window) {
requestIdleCallback(callback, { timeout: 1000 });
} else {
setTimeout(callback, 0);
}
}
优化处理时间(Processing Time)
// ❌ 事件处理中包含大量同步操作
button.addEventListener('click', () => {
// 同步数据处理
const result = processData(data);
// 同步 DOM 更新
updateDOM(result);
// 同步网络请求
fetch('/api/save', { method: 'POST', body: JSON.stringify(result) });
});
// ✅ 优化后:最小化同步操作
button.addEventListener('click', async () => {
// 立即提供视觉反馈
button.disabled = true;
showLoadingState();
// 使用 queueMicrotask 延迟非关键更新
queueMicrotask(() => {
// 数据处理移到微任务
const result = processData(data);
// 使用 requestAnimationFrame 批量 DOM 更新
requestAnimationFrame(() => {
updateDOM(result);
});
// 异步网络请求
fetch('/api/save', { method: 'POST', body: JSON.stringify(result) });
});
});
优化呈现延迟(Presentation Delay)
// ❌ 触发强制同步布局
element.addEventListener('click', () => {
// 修改样式
element.style.width = '100px';
// 立即读取布局信息 → 触发强制同步布局
const height = element.offsetHeight;
// 再次修改样式 → 布局失效
element.style.height = height + 'px';
});
// ✅ 读写分离,使用 transform
element.addEventListener('click', () => {
// 使用 transform 避免布局计算
element.style.transform = 'scale(1.1)';
// 批量读取
requestAnimationFrame(() => {
const rect = element.getBoundingClientRect();
// 批量写入
requestAnimationFrame(() => {
updateRelatedElements(rect);
});
});
});
CLS 优化策略 2026
CLS 来源分析
// 监控并分析 CLS 来源
const clsSources = [];
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (!entry.hadRecentInput) { // 排除用户交互导致的偏移
for (const source of entry.sources || []) {
clsSources.push({
value: entry.value,
element: source.node,
previousRect: source.previousRect,
currentRect: source.currentRect
});
}
}
}
});
observer.observe({ type: 'layout-shift', buffered: true });
2026 年 CLS 优化清单
<!-- 1. 图片和视频预留空间 -->
<img
src="/image.webp"
width="800"
height="600"
alt="..."
style="aspect-ratio: 800/600;"
/>
<!-- 2. 使用 CSS aspect-ratio -->
<style>
.video-container {
aspect-ratio: 16/9;
width: 100%;
}
</style>
<!-- 3. 为动态内容预留空间 -->
<style>
.ad-slot {
min-height: 250px; /* 广告最小高度 */
}
.skeleton {
min-height: 200px; /* 骨架屏占位 */
}
</style>
<!-- 4. 避免在现有内容上方插入内容 -->
<!-- ❌ 错误 -->
<div class="new-banner" style="position: relative;">新公告</div>
<!-- ✅ 正确:预留空间或使用 transform -->
<div class="banner-slot" style="min-height: 50px;">
<div class="new-banner">新公告</div>
</div>
搜索排名影响与应对策略
Core Web Vitals 在排名中的权重
根据 Google 官方说明和实际观察:
排名因素权重(估算):
├─ 内容相关性 ████████████████████ 40%+
├─ 反向链接质量 ████████████ 25%
├─ 页面体验信号
│ ├─ HTTPS ██ 5%
│ ├─ Mobile-Friendly ███ 7%
│ ├─ No Intrusive Interstitials ██ 3%
│ └─ Core Web Vitals ████ 8-10%
└─ 其他因素 █████ 10%
重要提示:
- Core Web Vitals 是"入围资格"而非"排名加分"
- 当内容质量相近时,性能优势更明显
- 差的 Core Web Vitals 可能导致排名下降
监控与预警系统
// 建立 Core Web Vitals 监控系统
interface VitalsThreshold {
good: number;
needsImprovement: number;
}
const thresholds: Record<string, VitalsThreshold> = {
LCP: { good: 2500, needsImprovement: 4000 },
INP: { good: 200, needsImprovement: 500 },
CLS: { good: 0.1, needsImprovement: 0.25 }
};
function analyzeVitals(metrics: Record<string, number>) {
const report = {};
for (const [name, value] of Object.entries(metrics)) {
const threshold = thresholds[name];
let status: 'good' | 'needs-improvement' | 'poor';
if (value <= threshold.good) {
status = 'good';
} else if (value <= threshold.needsImprovement) {
status = 'needs-improvement';
} else {
status = 'poor';
}
report[name] = { value, status };
// 触发告警
if (status === 'poor') {
sendAlert(`${name} 指标严重不达标: ${value}`);
}
}
return report;
}
总结
2026 年的 Core Web Vitals 以 INP 为核心,标志着性能评估从"首次加载"向"全程交互"的转变。
关键要点回顾
- ✅ INP 取代 FID:测量完整交互响应时间
- ✅ 三大指标协同:LCP(加载)+ INP(交互)+ CLS(稳定)
- ✅ 优化优先级:先保证 INP,再优化 LCP 和 CLS
- ✅ 持续监控:建立实时监控和预警机制
- ✅ 渐进优化:从高流量页面开始,逐步覆盖全站
立即行动
- 使用 web-vitals 库集成性能监控
- 在 Chrome DevTools 中检查慢交互
- 重点优化 INP > 200ms 的交互
- 建立周期性的性能审计流程


